0%

概述

Scrapy 是一个基于 Twisted 的异步处理框架,是纯 Python 实现的爬虫框架,其架构清晰,模块之间的耦合程度低,可扩展性极强,可以灵活完成各种需求。我们只需要定制开发几个模块就可以轻松实现一个爬虫。

scrapy 爬虫框架的架构如下图所示:

图片

1.

它有如下几个部分:

  • Scrapy Engine(引擎):用来处理整个系统的数据流处理、触发事务,是整个框架的核心。
  • Item(项目):定义了爬取结果的数据结构,爬取的数据会被赋值成该对象。
  • Scheduler(调度器):用来接受引擎发过来的请求并加入队列中,并在引擎再次请求的时候提供给引擎。
  • Item Pipeline(项目管道):负责处理由蜘蛛从网页中抽取的项目,它的主要任务是清洗、验证和存储数据。
  • Downloader(下载器):用于下载网页内容,并将网页内容返回给 Spiders。
  • Spiders(蜘蛛):其内定义了爬取的逻辑和网页的解析规则,它主要负责解析响应并生成提取结果和新的请求。
  • Downloader Middlewares(下载器中间件):位于引擎和下载器之间的钩子框架,主要是处理引擎与下载器之间的请求及响应。
  • Spider Middlewares(Spiders 中间件):位于引擎和蜘蛛之间的钩子框架,主要工作是处理蜘蛛输入的响应和输出的结果及新的请求。

通过多个组件的相互协作、不同组件完成工作的不同、组件很好地支持异步处理,scrapy 最大限度地利用了网络带宽,大大提高了数据爬取和处理的效率。

Scrapy 框架是通过命令行来创建项目的,创建项目的命令如下:

scrapy startproject practice

命令执行后,在当前运行目录下便会出现一个文件夹,叫作 practice ,这就是一个Scrapy 项目框架,我们可以基于这个项目框架来编写爬虫。

project/
 __pycache__
  spiders/
   __pycache__
        __init__.py
        spider1.py
        spider2.py
        ...
    __init__.py
    items.py
    middlewares.py
    pipelines.py
    settings.py
scrapy.cfg

各个文件的功能描述如下:

  • scrapy.cfg:它是 Scrapy 项目的配置文件,其内定义了项目的配置文件路径、部署相关信息等内容。
  • items.py:它定义 Item 数据结构,所有的 Item 的定义都可以放这里。
  • pipelines.py:它定义 Item Pipeline 的实现,所有的 Item Pipeline 的实现都可以放这里。
  • settings.py:它定义项目的全局配置。
  • middlewares.py:它定义 Spider Middlewares 和 Downloader Middlewares 的实现。
  • spiders:其内包含一个个 Spider 的实现,每个 Spider 都有一个文件。

2.

三、scrapy 的基本使用

实例 1:爬取 Quotes

  • 创建一个 Scrapy 项目。
  • 创建一个 Spider 来抓取站点和处理数据。
  • 通过命令行运行,将抓取的内容导出。

目标URL:http://quotes.toscrape.com/

创建项目

创建一个 scrapy 项目,项目文件可以直接用 scrapy 命令生成,命令如下所示:

scrapy startproject practice 

创建 Spider

Spider 是自己定义的类,scrapy 用它从网页里抓取内容,并解析抓取的结果。这个类必须继承 Scrapy 提供的Spider 类 scrapy.Spider ,还要定义 Spider 的名称和起始请求,以及怎样处理爬取后的结果的方法。

使用命令行创建一个 Spider,命令如下:

cd practice
scrapy genspider quotes quotes.toscrape.com

切换路径到刚才创建的 practice 文件夹,然后执行 genspider 命令。第一个参数是 Spider 的名称,第二个参数是网站域名。执行完毕之后,spiders 文件夹中多了一个quotes.py,它就是刚刚创建的 Spider,内容如下:

import scrapy

class QuotesSpider(scrapy.Spider):
    name = "quotes"
    allowed_domains = ["quotes.toscrape.com"]
    start_urls = ['http://quotes.toscrape.com/']

    def parse(self, response):
        pass

可以看到 quotes.py 里有三个属性—— name、allowed_domains 和 start_urls,还有一个方法 parse。

  • name:它是每个项目唯一的名字,用来区分不同的 Spider。
  • allowed_domains:它是允许爬取的域名,如果初始或后续的请求链接不是这个域名下的,则请求链接会被过滤掉。
  • start_urls:它包含了 Spider 在启动时爬取的 url 列表,初始请求是由它来定义的。
  • parse:它是 Spider 的一个方法。默认情况下,被调用时 start_urls 里面的链接构成的请求完成下载执行后,返回的响应就会作为唯一的参数传递给这个函数。该方法负责解析返回的响应、提取数据或者进一步生成要处理的请求。

创建 Item

Item 是保存爬取数据的容器,它的使用方法和字典类似。不过,相比字典,Item 多了额外的保护机制,可以避免拼写错误或者定义字段错误。

创建 Item 需要继承 scrapy.Item 类,并且定义类型为 scrapy.Field 的字段。观察目标网站,我们可以获取到的内容有 text、author、tags。

定义 Item ,此时进入 items.py 修改如下:

import scrapy

class QuoteItem(scrapy.Item):
    text = scrapy.Field()
    author = scrapy.Field()
    tags = scrapy.Field()

定义了三个字段,并将类的名称修改为 QuoteItem ,接下来爬取时会使用到这个 Item。

解析 Response

parse 方法的参数 response 是 start_urls 里面的链接爬取后的结果。所以在 parse 方法中,我们可以直接对 response 变量包含的内容进行解析,比如浏览请求结果的网页源代码,或者进一步分析源代码内容,或者找出结果中的链接而得到下一个请求。

图片

可以看到网页中既有想要提取的数据,又有下一页的链接,这两部分内容都可以进行处理。

首先看看网页结构,如图所示。每一页都有多个 class 为 quote 的区块,每个区块内都包含 text、author、tags。那么我们先找出所有的 quote,然后提取每一个 quote 中的内容。

提取数据的方式可以是 CSS 选择器 或 XPath 选择器

使用 Item

上文定义了 Item,接下来就要使用它了。Item 可以理解为一个字典,不过在声明的时候需要实例化。然后依次用刚才解析的结果赋值 Item 的每一个字段,最后将 Item 返回即可。

import scrapy
from practice.items import QuoteItem


class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    allowed_domains = ['quotes.toscrape.com']
    start_urls = ['http://quotes.toscrape.com/']

    def parse(self, response, **kwargs):
        quotes = response.css('.quote')
        for quote in quotes:
            item = QuoteItem()
            item['text'] = quote.css('.text::text').extract_first()
            item['author'] = quote.css('.author::text').extract_first()
            item['tags'] = quote.css('.tags .tag::text').extract()
            yield item

后续 Request

上面的操作实现了从初始页面抓取内容。实现翻页爬取,这就需要从当前页面中找到信息来生成下一个请求,然后在下一个请求的页面里找到信息再构造下一个请求。这样循环往复迭代,从而实现整站的爬取。

图片

查看网页源代码,可以发现下一页的链接是 /page/2/,但实际上全链接为:http://quotes.toscrape.com/page/2/,通过这个链接就可以构造下一个请求。

构造请求时需要用到 scrapy.Request。这里我们传递两个参数——url 和 callback,这两个参数的说明如下:

  • url:它是请求链接
  • callback:它是回调函数。当指定了该回调函数的请求完成之后,获取到响应,引擎会将该响应作为参数传递给这个回调函数。回调函数进行解析或生成下一个请求,回调函数如上文的 parse() 所示。

由于 parse 就是解析 text、author、tags 的方法,而下一页的结构和刚才已经解析的页面结构是一样的,所以我们可以再次使用 parse 方法来做页面解析。

"""
@Author  :叶庭云
@Date    :2020/10/2 11:40
@CSDN    :https://blog.csdn.net/fyfugoyfa
"""
import scrapy
from practice.items import QuoteItem


class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    allowed_domains = ['quotes.toscrape.com']
    start_urls = ['http://quotes.toscrape.com/']

    def parse(self, response, **kwargs):
        quotes = response.css('.quote')
        for quote in quotes:
            item = QuoteItem()
            item['text'] = quote.css('.text::text').extract_first()
            item['author'] = quote.css('.author::text').extract_first()
            item['tags'] = quote.css('.tags .tag::text').extract()
            yield item
        next_page = response.css('.pager .next a::attr("href")').extract_first()
        next_url = response.urljoin(next_page)
        yield scrapy.Request(url=next_url, callback=self.parse)

运行

接下来,进入目录,运行如下命令:

scrapy crawl quotes -o quotes.csv

命令运行后,项目内多了一个 quotes.csv 文件,文件包含了刚才抓取的所有内容。

图片

输出格式还支持很多种,例如 json、xml、pickle、marshal 等,还支持 ftp、s3 等远程输出,另外还可以通过自定义 ItemExporter 来实现其他的输出。

scrapy crawl quotes -o quotes.json
scrapy crawl quotes -o quotes.xml
scrapy crawl quotes -o quotes.pickle
scrapy crawl quotes -o quotes.marshal
scrapy crawl quotes -o ftp://user:pass@ftp.example.com/path/to/quotes.csv

其中,ftp 输出需要正确配置用户名、密码、地址、输出路径,否则会报错。

通过 scrapy 提供的 Feed Exports,我们可以轻松地输出抓取结果到文件,对于一些小型项目来说,这应该足够了。不过如果想要更复杂的输出,如输出到数据库等,可以灵活使用 Item Pileline 来完成。

实例 2:爬取图片

目标URL:http://sc.chinaz.com/tupian/dangaotupian.html

创建项目

scrapy startproject get_img
cd get_img
scrapy genspider img_spider sc.chinaz.com

构造请求

img_spider.py 中定义 start_requests() 方法,比如爬取这个网站里的蛋糕图片,爬取页数为 10 ,生成 10 次请求,如下所示:

def start_requests(self):
    for i in range(1, 11):
        if i == 1:
            url = 'http://sc.chinaz.com/tupian/dangaotupian.html'
        else:
            url = f'http://sc.chinaz.com/tupian/dangaotupian_{i}.html'
        yield scrapy.Request(url, self.parse)

编写 items.py

import scrapy


class GetImgItem(scrapy.Item):
    img_url = scrapy.Field()
    img_name = scrapy.Field()

编写 img_spider.py

Spider 类定义了如何爬取某个(或某些)网站,包括了爬取的动作(例如:是否跟进链接)以及如何从网页的内容中提取结构化数据(抓取item)

"""
@Author  :叶庭云
@Date    :2020/10/2 11:40
@CSDN    :https://blog.csdn.net/fyfugoyfa
"""
import scrapy
from get_img.items import GetImgItem


class ImgSpiderSpider(scrapy.Spider):
    name = 'img_spider'

    def start_requests(self):
        for i in range(1, 11):
            if i == 1:
                url = 'http://sc.chinaz.com/tupian/dangaotupian.html'
            else:
                url = f'http://sc.chinaz.com/tupian/dangaotupian_{i}.html'
            yield scrapy.Request(url, self.parse)

    def parse(self, response, **kwargs):
        src_list = response.xpath('//div[@id="container"]/div/div/a/img/@src2').extract()
        alt_list = response.xpath('//div[@id="container"]/div/div/a/img/@alt').extract()
        for alt, src in zip(alt_list, src_list):
            item = GetImgItem()       # 生成item对象
            # 赋值
            item['img_url'] = src
            item['img_name'] = alt
            yield item

编写管道文件 pipelines.py

Scrapy 提供了专门处理下载的 Pipeline ,包括文件下载和图片下载。下载文件和图片的原理与抓取页面的原理一样,因此下载过程支持异步和多线程,十分高效。

from scrapy.pipelines.images import ImagesPipeline  # scrapy图片下载器
from scrapy import Request
from scrapy.exceptions import DropItem

class GetImgPipeline(ImagesPipeline):
    # 请求下载图片
    def get_media_requests(self, item, info):
        yield Request(item['img_url'], meta={'name': item['img_name']})

    def item_completed(self, results, item, info):
        # 分析下载结果并剔除下载失败的图片
        image_paths = [x['path'] for ok, x in results if ok]
        if not image_paths:
            raise DropItem("Item contains no images")
        return item

    # 重写file_path方法,将图片以原来的名称和格式进行保存
    def file_path(self, request, response=None, info=None):
        name = request.meta['name']  # 接收上面meta传递过来的图片名称
        file_name = name + '.jpg'    # 添加图片后缀名
        return file_name

在这里实现了 GetImagPipeline,继承 Scrapy 内置的 ImagesPipeline,重写了下面几个方法:

  • get_media_requests()。它的第一个参数 item 是爬取生成的 Item 对象。我们将它的 url 字段取出来,然后直接生成 Request 对象。此 Request 加入调度队列,等待被调度,执行下载。
  • item_completed(),它是当单个 Item 完成下载时的处理方法。因为可能有个别图片未成功下载,所以需要分析下载结果并剔除下载失败的图片。该方法的第一个参数 results 就是该 Item 对应的下载结果,它是一个列表形式,列表每一个元素是一个元组,其中包含了下载成功或失败的信息。这里我们遍历下载结果找出所有成功的下载列表。如果列表为空,那么说明该 Item 对应的图片下载失败了,随即抛出异常DropItem,该 Item 忽略。否则返回该 Item,说明此 Item 有效。
  • file_path(),它的第一个参数 request 就是当前下载对应的 Request 对象。这个方法用来返回保存的文件名,接收上面meta传递过来的图片名称,将图片以原来的名称和定义格式进行保存。

配置文件 settings.py

# setting.py

BOT_NAME = 'get_img'

SPIDER_MODULES = ['get_img.spiders']
NEWSPIDER_MODULE = 'get_img.spiders'

# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

# Configure maximum concurrent requests performed by Scrapy (default: 16)
CONCURRENT_REQUESTS = 32

# Configure a delay for requests for the same website (default: 0)
# See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
DOWNLOAD_DELAY = 0.25

# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
   'get_img.pipelines.GetImgPipeline': 300,
}

IMAGES_STORE = './images'   # 设置保存图片的路径 会自动创建

运行程序:

# 切换路径到img_spider的目录
scrapy crawl img_spider

scrapy 框架爬虫一边爬取一边下载,下载速度非常快。

查看本地 images 文件夹,发现图片都已经成功下载

4.

5.

参考链接:

概述

一、Python3.6新特性

1、新的格式化字符串方式

新的格式化字符串方式,即在普通字符串前添加 fF 前缀,其效果类似于str.format()。比如

name = "red"
print(f"He said his name is {name}.") 
# 'He said his name is red.'

相当于:

print("He said his name is {name}.".format(**locals()))

此外,此特性还支持嵌套字段,比如:

import decimal   
width = 10
precision = 4  #精确的数目
value = decimal.Decimal("12.34567")
print(f"result: {value:{width}.{precision}}") 
#'result:  12.35'

2、变量声明语法

可以像下面一样声明一个变量并指定类型:

from typing import List, Dict

primes: List[int] = []
captain: str  # 此时没有初始值

class Starship:
  stats: Dict[str, int] = {}

感觉没啥用,在python中添加类型像傻子行为

官方解释:

就像函数注解一样,Python 解释器并不给变量注解附加任何特殊的含义,只将它们存储在类或模块的 annotations 属性中。

与静态类型语言中的变量声明相比,注释语法的目标是通过抽象语法树和 _annotations_ 属性为第三方工具和库提供一种简单的方法来指定结构化类型元数据。

3、数字的下划线写法

允许在数字中使用下划线,以提高多位数字的可读性。

a = 1_000_000_000_000_000    # 1000000000000000
b = 0x_FF_FF_FF_FF       # 4294967295

除此之外,字符串格式化也支持_选项,以打印出更易读的数字字符串:

'{:_}'.format(1000000)     # '1_000_000'
'{:_x}'.format(0xFFFFFFFF)   # 'ffff_ffff'

4、异步生成器

在Python3.5中,引入了新的语法 async 和 await 来实现协同程序。但是有个限制,不能在同一个函数体内同时使用 yield 和 await。Python3.6中,这个限制被放开了,允许定义异步生成器:

async def ticker(delay, to):
"""Yield numbers from 0 to *to* every *delay* seconds."""
  for i in range(to):
    yield i
    await asyncio.sleep(delay)

5、异步解析器

允许在列表list、集合set 和字典dict 解析器中使用 async 或 await 语法。

result = [i async for i in aiter() if i % 2]
result = [await fun() for fun in funcs if await condition()]

6、新增加模块

标准库(The Standard Library)中增加了一个新的模块:secrets。该模块用来生成一些安全性更高的随机数,用于管理passwords, account authentication, security tokens, 以及related secrets等数据。

7、其他新特性

  • 新的 PYTHONMALLOC 环境变量允许开发者设置内存分配器,以及注册debug钩子等。
  • asyncio模块更加稳定、高效,并且不再是临时模块,其中的API也都是稳定版的了。
  • typing模块也有了一定改进,并且不再是临时模块。
  • datetime.strftime 和 date.strftime 开始支持ISO 8601的时间标识符%G, %u, %V。
  • hashlib 和 ssl 模块开始支持OpenSSL1.1.0。
  • hashlib模块开始支持新的hash算法,比如BLAKE2, SHA-3 和 SHAKE。
  • Windows上的 filesystem 和 console 默认编码改为UTF-8。
  • json模块中的 json.load() 和 json.loads() 函数开始支持 binary 类型输入。

更多内容参考官方文档:What’s New In Python 3.6

二、Python3.7新特性

Python 3.7于2018年6月27日发布, 包含许多新特性和优化,增添了众多新的类,可用于数据处理、针对脚本编译和垃圾收集的优化以及更快的异步I/O,主要如下:

  • 用类处理数据时减少样板代码的数据类。
  • 一处可能无法向后兼容的变更涉及处理生成器中的异常。
  • 面向解释器的“开发模式”。
  • 具有纳秒分辨率的时间对象。
  • 环境中默认使用UTF-8编码的UTF-8模式。
  • 触发调试器的一个新的内置函数。

1、新增内置函数breakpoint()

使用该内置函数,相当于通过代码的方式设置了断点,会自动进入Pbd调试模式。

如果在环境变量中设置PYTHONBREAKPOINT=0会忽略此函数。并且,pdb 只是众多可用调试器之一,你可以通过设置新的 PYTHONBREAKPOINT 环境变量来配置想要使用的调试器。

下面有一个简单例子,用户需要输入一个数字,判断它是否和目标数字一样:

"""猜数字游戏"""

def guess(target):
    user_guess = input("请输入你猜的数 >>> ")
    if user_guess == target:
        return "你猜对了!"
    else:
        return "猜错了"


if __name__ == '__main__':
    a = 100
    print(guess(a))

不幸的是,即使猜的数和目标数一样,打印的结果也是‘猜错了’,并且没有任何异常或错误信息。

为了弄清楚发生了什么,我们可以插入一个断点,来调试一下。以往一般通过print大法或者IDE的调试工具,但现在我们可以使用 **breakpoint()**。

"""猜数字游戏"""


def guess(target):
    user_guess = input("请输入你猜的数 >>> ")
    breakpoint()   //加入这一行
    if user_guess == target:
        return "你猜对了!"
    else:
        return "猜错了"


if __name__ == '__main__':
    a = 100
    print(guess(a))

在 pdb 提示符下,我们可以调用 locals() 来查看当前的本地作用域的所有变量。(pdb 有大量的命令,你也可以在其中运行正常的Python 语句)

请输入你猜的数 >>> 100
> d:\work\for_test\py3_test\test.py(7)guess()
-> if user_guess == target:
(Pdb) locals()
{'target': 100, 'user_guess': '100'}
(Pdb) type(user_guess)
<class 'str'>

搞明白了,target是一个整数,而user_guess 是一个字符串,这里发生了类型对比错误。

2、类型和注解

从 Python 3.5 开始,类型注解就越来越受欢迎。对于那些不熟悉类型提示的人来说,这是一种完全可选的注释代码的方式,以指定变量的类型。

什么是注解?它们是关联元数据与变量的语法支持,可以是任意表达式,在运行时被 Python 计算但被忽略。注解可以是任何有效的 Python 表达式。

下面是个对比的例子:

# 不带类型注解
def foo(bar, baz):
# 带类型注解
def foo(bar: 'Describe the bar', baz: print('random')) -> 'return thingy':

上面的做法,其实是Python对自身弱类型语言的强化,希望获得一定的类型可靠和健壮度,向Java等语言靠拢。

在 Python 3.5 中,注解的语法获得标准化,此后,Python 社区广泛使用了注解类型提示。

但是,注解仅仅是一种开发工具,可以使用 PyCharm 等 IDE 或 Mypy 等第三方工具进行检查,并不是语法层面的限制。

我们前面的猜数程序如果添加类型注解,它应该是这样的:

"""猜数字游戏"""


def guess(target:str):
    user_guess:str = input("请输入你猜的数 >>> ")
    breakpoint()
    if user_guess == target:
        return "你猜对了!"
    else:
        return "猜错了"


if __name__ == '__main__':
    a:int = 100
    print(guess(a))

PyCharm会给我们灰色的规范错误提醒,但不会给红色的语法错误提示。

用注解作为类型提示时,有两个主要问题:启动性能和前向引用

  • 在定义时计算大量任意表达式相当影响启动性能,而且 typing 模块非常慢
  • 你不能用尚未声明的类型来注解

typing 模块如此缓慢的部分原因是,最初的设计目标是在不修改核心 CPython 解释器的情况下实现 typing 模块。随着类型提示变得越来越流行,这一限制已经被移除,这意味着现在有了对 typing 的核心支持。

而对于向前引用,看下面的例子:

class User:
    def __init__(self, name: str, prev_user: User) -> None:
        pass

错误在于 User类型还没有被声明,此时的 prev_user 不能定义为 User 类型。

为了解决这个问题,Python3.7 将注解的评估进行了推迟。并且,这项改动向后不兼容,需要先导入annotations,只有到Python 4.0后才会成为默认行为。

from __future__ import annotations

class User: 
    def __init__(self, name: str, prev_user: User) -> None:
        pass

或者如下面的例子:

class C:
    def validate_b(self, obj: B) -> bool:
        ...
class B:
    ...

3、新增dataclasses模块

这个特性可能是 Python3.7以后比较常用的,它有什么作用呢?

假如我们需要编写一个下面的类:

from datetime import datetime
import dateutil

class Article(object):
    def __init__(self, _id, author_id, title, text, tags=None, 
                 created=datetime.now(), edited=datetime.now()):
    self._id = _id
    self.author_id = author_id
    self.title = title
    self.text = text
    self.tags = list() if tags is None else tags
    self.created = created
    self.edited = edited

    if type(self.created) is str:
       self.created = dateutil.parser.parse(self.created)

    if type(self.edited) is str:
       self.edited = dateutil.parser.parse(self.edited)

    def __eq__(self, other):
        if not isinstance(other, self.__class__):
            return NotImplemented
        return (self._id, self.author_id) == (other._id, other.author_id)

    def __lt__(self, other):
        if not isinstance(other, self.__class__):
            return NotImplemented
        return (self._id, self.author_id) < (other._id, other.author_id)

    def __repr__(self):
        return '{}(id={}, author_id={}, title={})'.format(
                self.__class__.__name__, self._id, self.author_id, self.title)

大量的初始化属性要定义默认值,可能还需要重写一堆魔法方法,来实现类实例的打印、比较、排序和去重等功能。

如果使用dataclasses进行改造,可以写成这个样子:

from dataclasses import dataclass, field
from typing import List
from datetime import datetime
import dateutil

@dataclass(order=True)   //注意这里
class Article(object):
    _id: int
    author_id: int
    title: str = field(compare=False)
    text: str = field(repr=False, compare=False)
    tags: List[str] = field(default=list(), repr=False, compare=False)
    created: datetime = field(default=datetime.now(), repr=False, compare=False)
    edited: datetime = field(default=datetime.now(), repr=False, compare=False)

    def __post_init__(self):
       if type(self.created) is str:
           self.created = dateutil.parser.parse(self.created)

       if type(self.edited) is str:
           self.edited = dateutil.parser.parse(self.edited)

这使得类不仅容易设置,而且当我们创建一个实例并打印出来时,它还可以自动生成优美的字符串。在与其他类实例进行比较时,它也会有适当的行为。这是因为dataclasses除了帮我们自动生成 __init__ 方法外,还生成了一些其他特殊方法,如 repreq 和 hash 等。

repr(object)

返回包含一个对象的可打印表示形式的字符串。 对于许多类型来说,该函数会尝试返回的字符串将会与该对象被传递给 eval() 时所生成的对象具有相同的值,在其他情况下表示形式会是一个括在尖括号中的字符串,其中包含对象类型的名称与通常包括对象名称和地址的附加信息。 类可以通过定义 __repr__() 方法来控制此函数为它的实例所返回的内容。

Dataclasses 使用字段 field来完提供默认值,手动构造一个 field() 函数能够访问其他选项,从而更改默认值。例如,这里将 field 中的 default_factory 设置为一个 lambda 函数,该函数提示用户输入其名称。

from dataclasses import dataclass, field
class User:
    name: str = field(default_factory=lambda: input("enter name"))

4、生成器异常处理

在Python 3.7中,生成器引发StopIteration异常后,StopIteration异常将被转换成RuntimeError异常,那样它不会悄悄一路影响应用程序的堆栈框架。这意味着如何处理生成器的行为方面不太敏锐的一些程序会在Python 3.7中抛出RuntimeError。在Python 3.6中,这种行为生成一个弃用警告;在Python 3.7中,它将生成一个完整的错误。

一个简易的方法是使用try/except代码段,在StopIteration传播到生成器的外面捕获它。更好的解决方案是重新考虑如何构建生成器――比如说,使用return语句来终止生成器,而不是手动引发StopIteration。

5、开发模式

Python解释器添加了一个新的命令行开关:-X,让开发人员可以为解释器设置许多低级选项。

这种运行时的检查机制通常对性能有重大影响,但在调试过程中对开发人员很有用。

-X 激活的选项包括:

  • asyncio模块的调试模式。这为异步操作提供了更详细的日志记录和异常处理,而异常操作可能很难调试或推理。
  • 面向内存分配器的调试钩子。这对于编写CPython扩展件的那些人很有用。它能够实现更明确的运行时检查,了解CPython如何在内部分配内存和释放内存。
  • 启用faulthandler模块,那样发生崩溃后,traceback始终转储出去。

6、 高精度时间函数

Python 3.7中一类新的时间函数返回纳秒精度的时间值。尽管Python是一种解释型语言,但是Python的核心开发人员维克多•斯廷纳(Victor Stinner)主张报告纳秒精度的时间。最主要的原因是,在处理转换其他程序(比如数据库)记录的时间值时,可以避免丢失精度。

新的时间函数使用后缀_ns比如说,time.process_time()的纳秒版本是time.process_time_ns()。请注意,并非所有的时间函数都有对应的纳秒版本。

7、其他新特性

  • 字典现在保持插入顺序。这在 3.6 中是非正式的,但现在成为了官方语言规范。在大多数情况下,普通的 dict 能够替换 collections.OrderedDict
  • .pyc 文件具有确定性,支持可重复构建 —— 也就是说,总是为相同的输入文件生成相同的 byte-for-byte 输出。
  • 新增contextvars模块,针对异步任务提供上下文变量。
  • __main__中的代码会显示弃用警告(DeprecationWarning)。
  • 新增UTF-8模式。在Linux/Unix系统,将忽略系统的locale,使用UTF-8作为默认编码。在非Linux/Unix系统,需要使用-X utf8选项启用UTF-8模式。
  • 允许模块定义__getattr__、__dir__函数,为弃用警告、延迟import子模块等提供便利。
  • 新的线程本地存储C语言API。
  • 更新Unicode数据到11.0。

三、Python3.8新特性

Python3.8版本于2019年10月14日发布,以下是 Python 3.8 相比 3.7 的新增特性。

1、海象赋值表达式

新的语法 :=,将值赋给一个更大的表达式中的变量。它被亲切地称为 **“海象运算符”(walrus operator)**,因为它长得像海象的眼睛和象牙。

“海象运算符” 在某些时候可以让你的代码更整洁,比如:

在下面的示例中,赋值表达式可以避免调用 len () 两次:

if (n := len(a)) > 10:  
    print(f"List is too long ({n} elements, expected <= 10)")

类似的好处还可体现在正则表达式匹配中需要使用两次匹配对象的情况中,一次检测用于匹配是否发生,另一次用于提取子分组:

discount = 0.0  

if (mo := re.search(r'(\d+)% discount', advertisement)):    
    discount = float(mo.group(1)) / 100.0

此运算符也可用于配合 while 循环计算一个值,来检测循环是否终止,而同一个值又在循环体中再次被使用的情况:

# Loop over fixed length blocks 

while (block := f.read(256)) != '': 
    process(block)

或者出现于列表推导式中,在筛选条件中计算一个值,而同一个值又在表达式中需要被使用:

[clean_name.title() for name in names   

 if (clean_name := normalize('NFC', name)) in allowed_names]

请尽量将海象运算符的使用限制在清晰的场合中,以降低复杂性并提升可读性。

2、仅限位置形参

新增一个函数形参语法 / 用来指明某些函数形参必须使用仅限位置而非关键字参数的形式。

这种标记语法与通过 help () 所显示的使用 Larry Hastings 的 Argument Clinic 工具标记的 C 函数相同。

在下面的例子中,形参 a 和 b 为仅限位置形参,c 或 d 可以是位置形参或关键字形参,而 e 或 f 要求为关键字形参:

def f(a, b, /, c, d, *, e, f):  

    print(a, b, c, d, e, f)

以下是合法的调用:

f(10, 20, 30, d=40, e=50, f=60)

但是,以下均为不合法的调用:

f(10, b=20, c=30, d=40, e=50, f=60)   # b 不可以是一个关键字参数
f(10, 20, 30, 40, 50, f=60)           # e 必须是一个关键字参数

这种标记形式的一个用例是它允许纯 Python 函数完整模拟现有的用 C 代码编写的函数的行为。例如,内置的 pow () 函数不接受关键字参数:

def pow(x, y, z=None, /):   

    "Emulate the built in pow() function"   

    r = x ** y  

    return r if z is None else r%z

另一个用例是在不需要形参名称时排除关键字参数。例如,内置的 len () 函数的签名为 len (obj, /)。这可以排除如下这种笨拙的调用形式:

len(obj='hello')  # The "obj" keyword argument impairs readability

另一个益处是将形参标记为仅限位置形参将允许在未来修改形参名而不会破坏客户的代码。例如,在 statistics 模块中,形参名 dist 在未来可能被修改。这使得以下函数描述成为可能:

def quantiles(dist, /, *, n=4, method='exclusive')  
    ...

由于在 / 左侧的形参不会被公开为可用关键字,其他形参名仍可在 **kwargs 中使用:

>>> def f(a, b, /, **kwargs):   
...     print(a, b, kwargs) 
... 
>>> f(10, 20, a=1, b=2, c=3)         # a and b are used in two ways 
10 20 {'a': 1, 'b': 2, 'c': 3}

这极大地简化了需要接受任意关键字参数的函数和方法的实现。例如,下面是 collections 模块中的代码摘录:

class Counter(dict):    

    def __init__(self, iterable=None, /, **kwds):   

        # Note "iterable" is a possible keyword argument

3、f 字符串支持 =

增加 = 说明符用于 f-string。形式为 f'{expr=}' 的 f 字符串将扩展表示为表达式文本,加一个等于号,再加表达式的求值结果。例如:

>>> user = 'eric_idle'  
>>> member_since = date(1975, 7, 31)    
>>> f'{user=} {member_since=}'  

"user='eric_idle' member_since=datetime.date(1975, 7, 31)"

f 字符串格式说明符允许更细致地控制所要显示的表达式结果:

>>> delta = date.today() - member_since 

>>> f'{user=!s}  {delta.days=:,d}'  
'user=eric_idle  delta.days=16,075'

= 说明符将输出整个表达式,以便详细演示计算过程:

>>> print(f'{theta=}  {cos(radians(theta))=:.3f}')  
theta=30  cos(radians(theta))=0.866

4、 typing模块的改进

Python是动态类型语言,但可以通过typing模块添加类型提示,以便第三方工具验证Python代码。Python 3.8给typing添加了一些新元素,因此它能够支持更健壮的检查:

  • final修饰器和Final类型标注表明,被修饰或被标注的对象在任何时候都不应该被重写、继承,也不能被重新赋值。
  • Literal类型将表达式限定为特定的值或值的列表(不一定是同一个类型的值)。
  • TypedDict可以用来创建字典,其特定键的值被限制在一个或多个类型上。注意这些限制仅用于编译时确定值的合法性,而不能在运行时进行限制。

5、多进程共享内存

multiprocessing模块新增SharedMemory类,可以在不同的Python进城之间创建共享的内存区域。

在旧版本的Python中,进程间共享数据只能通过写入文件、通过网络套接字发送,或采用Python的pickle模块进行序列化等方式。共享内存提供了进程间传递数据的更快的方式,从而使得Python的多处理器和多内核编程更有效率。

共享内存片段可以作为单纯的字节区域来分配,也可以作为不可修改的类似于列表的对象来分配,其中能保存数字类型、字符串、字节对象、None对象等一小部分Python对象。

6、 新版本的pickle协议

Python的pickle模块提供了一种序列化和反序列化Python数据结构或实例的方法,可以将字典原样保存下来供以后读取。不同版本的Python支持的pickle协议不同,而3.8版本的支持范围更广、更强大、更有效的序列化。

Python 3.8引入的第5版pickle协议可以用一种新方法pickle对象,它能支持Python的缓冲区协议,如bytes、memoryviews或Numpy array等。新的pickle避免了许多在pickle这些对象时的内存复制操作。

NumPy、Apache Arrow等外部库在各自的Python绑定中支持新的pickle协议。新的pickle也可以作为Python 3.6和3.7的插件使用,可以从PyPI上安装。

7、性能改进

  • 许多内置方法和函数的速度都提高了20%~50%,因为之前许多函数都需要进行不必要的参数转换。
  • 一个新的opcode缓存可以提高解释器中特定指令的速度。但是,目前实现了速度改进的只有LOAD_GLOBAL opcode,其速度提高了40%。以后的版本中也会进行类似的优化。
  • 文件复制操作如shutil.copyfile()shutil.copytree()现在使用平台特定的调用和其他优化措施,来提高操作速度。
  • 新创建的列表现在平均比以前小了12%,这要归功于列表构造函数如果能提前知道列表长度的情况下,可以进行优化。
  • Python 3.8中向新型类(如class A(object))的类变量中的写入操作变得更快。operator.itemgetter()和collections.namedtuple()也得到了速度优化。

更多详细特性,请查阅Python 3.8.0文档:https://docs.python.org/zh-cn/3.8/whatsnew/3.8.html

四、Python3.9新特性

Python 3.9 是最后一个提供 Python 2 向下兼容层的版本,以给予 Python 项目维护者更多时间移除 Python 2 支持,添加 Python 3.9 支持。

1.字典更新和合并

字典添加两个新的运算符:||=|运算符用于合并字典,|=运算符用于更新字典。

字典合并:

x={"a":"A","b":"B"}
y={"c":"C","d":"D"}
x|y  # {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'D'}
x|=y  # 等同于:x=x|y

2.标准多项集中的类型标注泛型

在类型标注中现在你可以使用内置多项集类型例如 listdict 作为通用类型而不必从 typing 导入对应的大写形式类型名 (例如 ListDict)。

def greet_all(names: list[str]) -> None:
    for name in names:
        print("Hello", name)

3.移除前缀和后缀的字符串方法

其他

zoneinfo

from from zoneinfo import ZoneInfo
from datetime import datetime,timedelta

dt = datetime(2020, 10, 31, 12, tzinfo=ZoneInfo("America/Los_Angeles"))
print(dt)

结果报错。。。。,不管了,反正我应该用不到

image-20210115114607890

math

math.gcd() 函数进行了扩展以处理多个参数。 在之前版本中,它只支持两个参数。

增加了 math.lcm(): 返回指定参数的最小公倍数。

增加了 math.nextafter(): 返回从 xy 方向的下一个浮点数值。

增加了 math.ulp(): 返回一个浮点数的最小有效比特位。

新的解析器

Python 3.9 使用于基于 PEG 的新解析器替代 LL(1)。 新解析器的性能与旧解析器大致相当,但 PEG 在设计新语言特性时的形式化比 LL(1) 更灵活。 我

参考链接:

概述

整理下我用过的一些好用的软件

软件名 功能 评价
everything 搜索电脑里的文件
HTTrack Website Copier 将网站离线到本地 没咋用过,最新版是2017年

1.漫步白月光

一个致力于便携软件的破解网站,也是我最喜欢的破解网站

软件名 功能 网盘链接
多窗口文件管理器 Q-Dir 9.0.9.0 中文绿色便携版 具有四个文件夹整理窗口的文件管理器,再加上额外的文件夹树窗口,就是五个窗口了。 https://www.lanzoux.com/b398945/
腾讯TIM v3.3.0.21970 绿色精简防撤回显IP便携版 消息防撤回:禁止对方消息被撤回,即对方发送消息撤回后你这依然可以看到; https://www.lanzoux.com/b936184
DeepL Pro 1.17.1 中文解锁安装版 CAT工具集成:自由翻译,翻译机构,语言服务提供商或公司语言部门都可以在其CAT工具中使用世界上最好的机器翻译技术DeepL Pro来受益。 https://mo.own-cloud.cn/#/s/L8RlU3?path=%2F
电子书转换器 Calibre 5.9 Ebook Edit 绿色便携版 支持转换多种格式。输入格式:CBZ,CBR,CBC,EPUB,FB2,HTML,LIT,LRF,MOBI,ODT,PDF,PRC **,PDB,PML,RB,RTF,TCR,TXT。输出格式:EPUB,FB2,OEB,LIT,LRF,MOBI,PDB,PML,RB,PDF,TCR,TXT。转换有许多选项,例如更改字体大小,创建书籍和脚注的结构等。 https://mo.own-cloud.cn/#/s/3kbyty?path=%2F
系统优化工具 Wise Care 365 v5.6.2.558 绿色专业便携版 —已爆力进门钥匙,无需授权码,即为永久专业版,享受所有功能!
VMware Workstation v16.1.0 精简特别版 修改添加 APPLE OSK,可以安装 MAC OS X
重复文件查找 Auslogics Duplicate File Finder 9.0.0.2 绿色便携版
Windows10开始菜单增强工具 StartIsBack++ v2.9.8 完整中文完整解锁版
网易有道词典 v8.9.6.0 去广告纯净版及经典版
微软常用运行库 Visual C++ Redistributable Runtimes AIO Repack 20210110 https://www.lanzoux.com/b123247/
格式工厂 Format Factory v5.6.0 x64 最新去广告绿色纯净便携版 https://www.lanzoux.com/b180677/
驱动人生 国际版 Driver Talent 8.0.0.6 去广告绿色中文便携版 单文件版 https://www.lanzoux.com/b133109/
批量重命名工具 Advanced Renamer 3.87 中文绿色便携版下载 https://wwa.lanzoux.com/b359479/
卸载利器 Geek Uninstaller 1.4.7.142 去升级免费便携版 https://www.lanzous.com/b126787/
PDF编辑软件 AlterPDF Pro 5.0 绿色便携版 https://www.lanzoux.com/b04m354yd
PDF工具箱 PDF Shaper Professional 9.7 / 10.7 简体中文专业版绿色便携版 https://wwa.lanzoux.com/b189443/

2.

3.

4.

5.

参考链接:

概述

CI/CD 是一种通过在应用开发阶段引入自动化来频繁向客户交付应用的方法。CI/CD 的核心概念是持续集成、持续交付和持续部署。作为一个面向开发和运营团队的解决方案,CI/CD 主要针对在集成新代码时所引发的问题(亦称:“集成地狱”)。

具体而言,CI/CD 可让持续自动化和持续监控贯穿于应用的整个生命周期(从集成和测试阶段,到交付和部署)。这些关联的事务通常被统称为“CI/CD 管道”,由开发和运维团队以敏捷方式协同支持。

CI 是什么?CI 和 CD 有什么区别?

缩略词 CI / CD 具有几个不同的含义。CI/CD 中的“CI”始终指持续集成,它属于开发人员的自动化流程。成功的 CI 意味着应用代码的新更改会定期构建、测试并合并到共享存储库中。该解决方案可以解决在一次开发中有太多应用分支,从而导致相互冲突的问题。

CI/CD 中的“CD”指的是持续交付和/或持续部署,这些相关概念有时会交叉使用。两者都事关管道后续阶段的自动化,但它们有时也会单独使用,用于说明自动化程度。

持续交付通常是指开发人员对应用的更改会自动进行错误测试并上传到存储库(如 GitHub 或容器注册表),然后由运维团队将其部署到实时生产环境中。这旨在解决开发和运维团队之间可见性及沟通较差的问题。因此,持续交付的目的就是确保尽可能减少部署新代码时所需的工作量。

持续部署(另一种“CD”)指的是自动将开发人员的更改从存储库发布到生产环境,以供客户使用。它主要为了解决因手动流程降低应用交付速度,从而使运维团队超负荷的问题。持续部署以持续交付的优势为根基,实现了管道后续阶段的自动化。

1.具体含义

CI 持续集成(Continuous Integration)

现代应用开发的目标是让多位开发人员同时处理同一应用的不同功能。但是,如果企业安排在一天内将所有分支源代码合并在一起(称为“合并日”),最终可能造成工作繁琐、耗时,而且需要手动完成。这是因为当一位独立工作的开发人员对应用进行更改时,有可能会与其他开发人员同时进行的更改发生冲突。如果每个开发人员都自定义自己的本地集成开发环境(IDE),而不是让团队就一个基于云的 IDE 达成一致,那么就会让问题更加雪上加霜。

持续集成(CI)可以帮助开发人员更加频繁地(有时甚至每天)将代码更改合并到共享分支或“主干”中。一旦开发人员对应用所做的更改被合并,系统就会通过自动构建应用并运行不同级别的自动化测试(通常是单元测试和集成测试)来验证这些更改,确保这些更改没有对应用造成破坏。这意味着测试内容涵盖了从类和函数到构成整个应用的不同模块。如果自动化测试发现新代码和现有代码之间存在冲突,CI 可以更加轻松地快速修复这些错误。


CD 持续交付(Continuous Delivery)

完成 CI 中构建及单元测试和集成测试的自动化流程后,持续交付可自动将已验证的代码发布到存储库。为了实现高效的持续交付流程,务必要确保 CI 已内置于开发管道。持续交付的目标是拥有一个可随时部署到生产环境的代码库。

在持续交付中,每个阶段(从代码更改的合并,到生产就绪型构建版本的交付)都涉及测试自动化和代码发布自动化。在流程结束时,运维团队可以快速、轻松地将应用部署到生产环境中。


CD 持续部署(Continuous Deployment)

对于一个成熟的 CI/CD 管道来说,最后的阶段是持续部署。作为持续交付——自动将生产就绪型构建版本发布到代码存储库——的延伸,持续部署可以自动将应用发布到生产环境。由于在生产之前的管道阶段没有手动门控,因此持续部署在很大程度上都得依赖精心设计的测试自动化。

实际上,持续部署意味着开发人员对应用的更改在编写后的几分钟内就能生效(假设它通过了自动化测试)。这更加便于持续接收和整合用户反馈。总而言之,所有这些 CI/CD 的关联步骤都有助于降低应用的部署风险,因此更便于以小件的方式(而非一次性)发布对应用的更改。不过,由于还需要编写自动化测试以适应 CI/CD 管道中的各种测试和发布阶段,因此前期投资还是会很大。

那么 CI/CD 到底是什么样的?

2.

3.

4.

5.

参考链接:

总览

邮箱 github 用户名 Heroku 用户名 密码 Google Outlook Kubesail IBM
qazplm1wsd@gmail.com
guke1800@gmail.com
guk1880@gmail.com
guke@lvyelanshan.top
guke6523@gmail.com
1097629344@qq.com
13430138475@139.com
19849410145@139.com
19849410145@189.cn
13430138475@189.cn
3119006870@mail2.gdut.edu.cn
guke@guke.ga guke-od.onemanage
guke1@guke.ga
guke2@guke.ga
guke3@guke.ga
guke4@guke.ga
guke5@guke.ga
guke6@guke.ga
guke7@guke.ga
guke8@guke.ga
guke9@guke.ga
guke10@guke.ga
3119006886@mail2.gdut.edu.cn

1.

2.

3.

4.

5.

参考链接:

概述

1.安装

官方的安装方法在在打包打包并分发应用程序时会出现门题和报错,难受,不过google有解决办法,或者按照博主的这个方法

1,安装node.js

  进入官网下载、安装。https://nodejs.org/en/

2,安装cnpm(可选,未安装则使用npm

  安装命令(打开系统的cmd.exe来执行命令): npm install -g cnpm –registry=https://registry.npm.taobao.org

检查是否安装成功,输出版本号即成功

node -v
npm -v

3,安装Electron

  安装命令: cnpm install -g electron

4,安装Electron-forge

  Electron工具整合项目:https://github.com/electron-userland/electron-forge

  安装命令: cnpm install -g electron-forge

5,新建项目

  F盘新建Electron项目文件夹 F:\Electron。

  在Electron文件夹下,按住Shift键并右键单击空白处,选择在此处打开命令窗口来启动cmd.exe。

  执行 electron-forge init 项目名称 命令来生成名为myapp的项目文件夹,同时安装项目所需要的模块、依赖项等。

  命令: electron-forge init myapp

6,启动项目

  cd到myapp目录下,执行命令 electron-forge start 来启动app(也可以简单的用npm start来运行)。

7,项目文件

  项目的目录结构:node_modules 文件夹下是各种模块、类库,src下是app的源代码文件,package.json是描述包的文件。

  src/index.js:这是app主进程的入口,在这里创建了mainWindow浏览器窗口,

  使用mainWindow.loadURL(\file://${__dirname}/index.html`)来加载index.html主页,

  我们也可以在此链接我们需要链接的网址,来实现web桌面应用,例:mainWindow.loadURL(https://www.cnblogs.com/),

  使用mainWindow.webContents.openDevTools()`来打开开发者工具用于调试(这个操作通常在发布app时删除)。

  然后是app的事件处理:

  ready: 当Electron完成初始化后触发,这里初始化后就会去创建浏览器窗口并加载主页面。
  window-all-closed: 当所有浏览器窗口被关闭后触发,一般此时就退出应用了。
  activate: 当app激活时触发,一般针对macOS要需要处理。

  src/index.html:这是主页面,除了显示Well hey there!!!的信息外,没什么具体内容。

9,编译打包

  输入以下命令进行编译打包: npm run make

  修改package.json,在electronPackagerConfig部分添加”asar”: true。
  “electronPackagerConfig”: {
    “asar”: true
  }
  重新打包后源码文件会被打包进app.asar文件中(该文件仍然在src目录下)。

  可以直接运行打包后的myapp.exe启动程序

2.基础文件

main.js

//main.js
const { app, BrowserWindow } = require('electron')

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win

function createWindow () {
  // 创建浏览器窗口。
  win = new BrowserWindow({ width: 800, height: 600 })

  // 然后加载应用的 index.html。对应的index.html 就是初始界面。
  win.loadFile('index.html')

  // 打开开发者工具
  win.webContents.openDevTools()

  //关于win 窗口的生命周期我们之后再研究……
  // 当 window 被关闭,这个事件会被触发。
  win.on('closed', () => {
    // 取消引用 window 对象,如果你的应用支持多窗口的话,
    // 通常会把多个 window 对象存放在一个数组里面,
    // 与此同时,你应该删除相应的元素。
    win = null
  })
}
//关于 app 主进程的生命周期我们之后再研究……
// Electron 会在初始化后并准备
// 创建浏览器窗口时,调用这个函数。
// 部分 API 在 ready 事件触发后才能使用。
app.on('ready', createWindow)

// 当全部窗口关闭时退出。
app.on('window-all-closed', () => {
  // 在 macOS 上,除非用户用 Cmd + Q 确定地退出,
  // 否则绝大部分应用及其菜单栏会保持激活。
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', () => {
  // 在macOS上,当单击dock图标并且没有其他窗口打开时,
  // 通常在应用程序中重新创建一个窗口。
  if (win === null) {
    createWindow()
  }
})

// 在这个文件中,你可以续写应用剩下主进程代码。
// 也可以拆分成几个文件,然后用 require 导入。

index.html

package.json

{
    "name": "我的-electron-app",
    "version": "0.1.0",
    "author": "古客",
    "description": "My Electron app",
    "main": "main.js",
    "scripts": {
        "start": "electron ."
    }
}

  “productName”: “myapp” 打包后的文件名称

  “version”: “1.0.0” 版本号

  若想更换打包程序的图标,可以在config->electronPackagerConfig->icon中进行设置,

  (例如:我们把app.ico放在src目录下就可以这样配置”icon”:”src/favicon.ico”)

3.

4.

5.

参考链接:

概述

安装可以看《JAVA连接SQLite

还可以安装DB Browser for SQLite,一个可视化的软件,降低数据库的使用难度

1.

尝试使用 .show 命令,来查看 SQLite 命令提示符的默认设置。

2.

3.

4.

5.附录

常用命令

命令 描述
.backup ?DB? FILE 备份 DB 数据库(默认是 “main”)到 FILE 文件。
.bail ON|OFF 发生错误后停止。默认为 OFF。
.databases 列出数据库的名称及其所依附的文件。
.dump ?TABLE? 以 SQL 文本格式转储数据库。如果指定了 TABLE 表,则只转储匹配 LIKE 模式的 TABLE 表。
.echo ON|OFF 开启或关闭 echo 命令。
.exit 退出 SQLite 提示符。
.explain ON|OFF 开启或关闭适合于 EXPLAIN 的输出模式。如果没有带参数,则为 EXPLAIN on,即开启 EXPLAIN。
.header(s) ON|OFF 开启或关闭头部显示。
.help 显示消息。
.import FILE TABLE 导入来自 FILE 文件的数据到 TABLE 表中。
.indices ?TABLE? 显示所有索引的名称。如果指定了 TABLE 表,则只显示匹配 LIKE 模式的 TABLE 表的索引。
.load FILE ?ENTRY? 加载一个扩展库。
.log FILE|off 开启或关闭日志。FILE 文件可以是 stderr(标准错误)/stdout(标准输出)。
.mode MODE 设置输出模式,MODE 可以是下列之一:csv 逗号分隔的值column 左对齐的列html HTML 的 代码insert TABLE 表的 SQL 插入(insert)语句line 每行一个值list 由 .separator 字符串分隔的值tabs 由 Tab 分隔的值tcl TCL 列表元素
.nullvalue STRING 在 NULL 值的地方输出 STRING 字符串。
.output FILENAME 发送输出到 FILENAME 文件。
.output stdout 发送输出到屏幕。
.print STRING… 逐字地输出 STRING 字符串。
.prompt MAIN CONTINUE 替换标准提示符。
.quit 退出 SQLite 提示符。
.read FILENAME 执行 FILENAME 文件中的 SQL。
.schema ?TABLE? 显示 CREATE 语句。如果指定了 TABLE 表,则只显示匹配 LIKE 模式的 TABLE 表。
.separator STRING 改变输出模式和 .import 所使用的分隔符。
.show 显示各种设置的当前值。
.stats ON|OFF 开启或关闭统计。
.tables ?PATTERN? 列出匹配 LIKE 模式的表的名称。
.timeout MS 尝试打开锁定的表 MS 毫秒。
.width NUM NUM 为 “column” 模式设置列宽度。
.timer ON|OFF 开启或关闭 CPU 定时器。
参考链接:

概述

正则表达式是一个非常实用的工具,特别是处理大量文本的时候

像博主之前做了个返回随机二次元图片的cf-worker,需要对图片的直链变成json格式的,在网上找了一圈都没有合适的,

但是对json的处理还是没有弄好

1.符号

字符 描述
\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个向后引用、或一个八进制转义符。例如,“n”匹配字符“n”。“\n”匹配一个换行符。串行“\\”匹配“\”而“\(”则匹配“(”。
^ 匹配输入字符串的开始位置。如果设置了RegExp对象的Multiline属性,^也匹配“\n”或“\r”之后的位置。
$ 匹配输入字符串的结束位置。如果设置了RegExp对象的Multiline属性,$也匹配“\n”或“\r”之前的位置。
* 匹配前面的子表达式零次或多次。例如,zo能匹配“z”以及“zoo”。等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价于{1,}。
? 匹配前面的子表达式零次或一次。例如,“do(es)?”可以匹配“does”或“does”中的“do”。?等价于{0,1}。
{n} n是一个非负整数。匹配确定的n次。例如,“o{2}”不能匹配“Bob”中的“o”,但是能匹配“food”中的两个o。
{n,} n是一个非负整数。至少匹配n次。例如,“o{2,}”不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。“o{1,}”等价于“o+”。“o{0,}”则等价于“o*”。
{n,m} mn均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,“o{1,3}”将匹配“fooooood”中的前三个o。“o{0,1}”等价于“o?”。请注意在逗号和两个数之间不能有空格。
? 当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串“oooo”,“o+?”将匹配单个“o”,而“o+”将匹配所有“o”。
. 匹配除“\*n”之外的任何单个字符。要匹配包括“\n*”在内的任何字符,请使用像“`(.
(pattern) 匹配pattern并获取这一匹配。所获取的匹配可以从产生的Matches集合得到,在VBScript中使用SubMatches集合,在JScript中则使用$0…$9属性。要匹配圆括号字符,请使用“\(”或“\)”。
(?:pattern) 匹配pattern但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用或字符“`(
(?=pattern) 正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“`Windows(?=95
(?!pattern) 正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如“`Windows(?!95
(?<=pattern) 反向肯定预查,与正向肯定预查类拟,只是方向相反。例如,“`(?<=95
(?<!pattern) 反向否定预查,与正向否定预查类拟,只是方向相反。例如“`(?<!95
x|y 匹配x或y。例如,“`z
[xyz] 字符集合。匹配所包含的任意一个字符。例如,“[abc]”可以匹配“plain”中的“a”。
[^xyz] 负值字符集合。匹配未包含的任意字符。例如,“[^abc]”可以匹配“plain”中的“p”。
[a-z] 字符范围。匹配指定范围内的任意字符。例如,“[a-z]”可以匹配“a”到“z”范围内的任意小写字母字符。
[^a-z] 负值字符范围。匹配任何不在指定范围内的任意字符。例如,“[^a-z]”可以匹配任何不在“a”到“z”范围内的任意字符。
\b 匹配一个单词边界,也就是指单词和空格间的位置。例如,“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”。
\B 匹配非单词边界。“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。
\cx 匹配由x指明的控制字符。例如,\cM匹配一个Control-M或回车符。x的值必须为A-Z或a-z之一。否则,将c视为一个原义的“c”字符。
\d 匹配一个数字字符。等价于[0-9]。
\D 匹配一个非数字字符。等价于[^0-9]。
\f 匹配一个换页符。等价于\x0c和\cL。
\n 匹配一个换行符。等价于\x0a和\cJ。
\r 匹配一个回车符。等价于\x0d和\cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。
\S 匹配任何非空白字符。等价于[^ \f\n\r\t\v]。
\t 匹配一个制表符。等价于\x09和\cI。
\v 匹配一个垂直制表符。等价于\x0b和\cK。
\w 匹配包括下划线的任何单词字符。等价于“[A-Za-z0-9_]”。
\W 匹配任何非单词字符。等价于“[^A-Za-z0-9_]”。
\xn 匹配n,其中n为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,“\x41”匹配“A”。“\x041”则等价于“\x04&1”。正则表达式中可以使用ASCII编码。.
*num* 匹配num,其中num是一个正整数。对所获取的匹配的引用。例如,“(.)\1”匹配两个连续的相同字符。
*n* 标识一个八进制转义值或一个向后引用。如果*n之前至少n个获取的子表达式,则n为向后引用。否则,如果n为八进制数字(0-7),则n*为一个八进制转义值。
*nm* 标识一个八进制转义值或一个向后引用。如果*nm之前至少有nm个获得子表达式,则nm为向后引用。如果*nm之前至少有n个获取,则n为一个后跟文字m的向后引用。如果前面的条件都不满足,若nm均为八进制数字(0-7),则*nm将匹配八进制转义值nm*。
*nml* 如果n为八进制数字(0-3),且m和l均为八进制数字(0-7),则匹配八进制转义值nml。
\un 匹配n,其中n是一个用四个十六进制数字表示的Unicode字符。例如,\u00A9匹配版权符号(©)。

非打印字符

非打印字符也可以是正则表达式的组成部分。下表列出了表示非打印字符的转义序列:

字符 描述
\cx 匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 ‘c’ 字符。
\f 匹配一个换页符。等价于 \x0c 和 \cL。
\n 匹配一个换行符。等价于 \x0a 和 \cJ。
\r 匹配一个回车符。等价于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意 Unicode 正则表达式会匹配全角空格符。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t 匹配一个制表符。等价于 \x09 和 \cI。
\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。

特殊字符

所谓特殊字符,就是一些有特殊含义的字符,如上面说的 runoo*b 中的 *****,简单的说就是表示任何字符串的意思。如果要查找字符串中的 ***** 符号,则需要对 ***** 进行转义,即在其前加一个 **: runo*ob 匹配 runo*ob。

许多元字符要求在试图匹配它们时特别对待。若要匹配这些特殊字符,必须首先使字符”转义”,即,将反斜杠字符** 放在它们前面。下表列出了正则表达式中的特殊字符:

特别字符 描述
$ 匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 ‘\n’ 或 ‘\r’。要匹配 $ 字符本身,请使用 $。
( ) 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 ( 和 )。
* 匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 *。
+ 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 +。
. 匹配除换行符 \n 之外的任何单字符。要匹配 . ,请使用 . 。
[ 标记一个中括号表达式的开始。要匹配 [,请使用 [。
? 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 ?。
\ 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, ‘n’ 匹配字符 ‘n’。’\n’ 匹配换行符。序列 ‘\‘ 匹配 “",而 ‘(‘ 则匹配 “(“。
^ 匹配输入字符串的开始位置,除非在方括号表达式中使用,当该符号在方括号表达式中使用时,表示不接受该方括号表达式中的字符集合。要匹配 ^ 字符本身,请使用 ^。
{ 标记限定符表达式的开始。要匹配 {,请使用 {。
| 指明两项之间的一个选择。要匹配 |,请使用 |。

常用正则表达式

用户名 /^[a-z0-9_-]{3,16}$/
密码 /^[a-z0-9_-]{6,18}$/
十六进制值 /^#?([a-f0-9]{6}|[a-f0-9]{3})$/
电子邮箱 /^([a-z0-9_.-]+)@([\da-z.-]+).([a-z.]{2,6})$/ /^[a-z\d]+(.[a-z\d]+)*@(\da-z?)+(.{1,2}[a-z]+)+$/
URL /^(https?://)?([\da-z.-]+).([a-z.]{2,6})([/\w .-]*)*/?$/
IP 地址 /((2[0-4]\d|25[0-5]|[01]?\d\d?).){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)/ /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
HTML 标签 /^<([a-z]+)([^<]+)(?:>(.)</\1>|\s+/>)$/
删除代码\注释 (?<!http:|\S)//.*$
Unicode编码中的汉字范围 /^[\u2E80-\u9FFF]+$/

2.示例

  • runoo+b,可以匹配 runoob、runooob、runoooooob 等,+ 号代表前面的字符必须至少出现一次(1次或多次)。
  • runoo*b,可以匹配 runob、runoob、runoooooob 等,* 号代表前面的字符可以不出现,也可以出现一次或者多次(0次、或1次、或多次)。
  • colou?r 可以匹配 color 或者 colour,? 问号代表前面的字符最多只可以出现一次(0次、或1次)。

匹配 […] 中的所有字符,例如 [aeiou] 匹配字符串 “google runoob taobao” 中所有的 e o u a 字母。

匹配除了 […] 中字符的所有字符,例如 [^aeiou] 匹配字符串 “google runoob taobao” 中除了 e o u a 字母的所有字母。

以下正则表达式匹配一个正整数,**[1-9]设置第一个数字不是 0,[0-9]*** 表示任意多个数字:

/[1-9][0-9]*/

3.实战

测试地址

4.在JavaScript中使用正则

MDN

参考链接:

概述

总所周知,如果我们想让文章能被更多的人看到,应该尽可能的在多个平台进行发布,国内比较著名的有博客园,简书CSDN,知乎等等

一图胜千言

平台 传播性 易用性 专一和影响力 其他功能 是否支持markdown 地址
CSDN ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐ www.csdn.net/
博客园 ⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐⭐ www.cnblogs.com/
知乎专栏 ⭐⭐⭐ ⭐⭐⭐⭐ zhuanlan.zhihu.com/
segmentfault ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐ segmentfault.com/blog/samdyl…
掘金 ⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐ juejin.im/
头条号
简书 ⭐⭐⭐ ⭐⭐⭐ www.jianshu.com/
github page ⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐ pages.github.com/
自建站点 ⭐⭐ ⭐⭐ ⭐⭐

如果你想自己做一个博客,可以看看这篇《14个最好的免费博客平台

自建博客的收录是真的难受,除了谷歌收录了一些,其他搜索引擎几乎没有收录

1.

可看这个 ,

博主推荐:

浏览器插件:微信公众号同步助手,支持markdown

PC端:蚁小二,

复制到这里,发布即可

2.

3.

4.

5.

参考链接:

VLOOK™
让你的 Markdown 有了新看法
──
脚本化图表参考指南


MAX_孟兆
COPYRIGHT © 2017-2020. MAX°DESIGN.

[TOC]

关于 Markdown

Markdown 是什么?

十四年前,John Gruber 创造了 Markdown,一种专门针对网络写作的文本标记语言。使用 Markdown,你只需在写作过程中插入少量的标记符号,就能很轻松地进行排版(例如设置标题、加粗、列表、引用等)。

Markdown 文档以纯文本格式存储,这意味着,它们可以用几乎任一种文本编辑器打开。同时,又能通过 Markdown 编辑器导出为带排版的富文本文档、HTML 网页等等。纯粹、简洁、易用、灵活,都是人们喜欢 Markdown 的原因。目前 Markdown 的标准化项目是 CommonMark

Markdown 语法参考:

主推方案 (Mermaid)

mermaid 是一个用于画流程图、状态图、顺序图、甘特图的库,使用 JS 进行本地渲染,广泛集成于许多 Markdown 编辑器中。详见 mermaid 官网

流程图

![流程图]”(以上的「分支流程」内容由下图进行接续)”
graph LR
START(开始) --> node1(普通节点)
subgraph 子图
	node1 --> |情况1|groud1[流程组节点]
  node1 --> |情况2|A1((A))
end

%% this is a comment

groud1 ==> |重要分支|cond1{条件判断}
cond1 --> |是|END
cond1 -.-> |否|page2>分支流程]
A2((A)) --> END
END(结束)
分支流程(接续上图)
graph LR
page2>分支流程] --> node2(普通节点)
node2 --> END
END(结束)
以上「流程图」的画图脚本示例
graph LR
START(开始) --> node1(普通节点)
subgraph 子图
	node1 --> |情况1|groud1[流程组节点]
  node1 --> |情况2|A1((A))
end

%% this is a comment

groud1 ==> |重要分支|cond1{条件判断}
cond1 --> |是|END
cond1 -.-> |否|page2>分支流程]
A2((A)) --> END
END(结束)
说明
  1. 针对流程图及不同图元的应用,重绘为不同的外观、形状;

  2. 特定节点命名规范:

    • START:开始结点
    • END:结束结点
  3. 支持节点形状/类型:

    节点形状 应用建议 说明
    圆角矩形 普通流程节点 结合别名(如:node1、page2 等,可自由定义),并通过()指定,举例:node1(普通节点)
    菱形 条件判断节点 结合别名,并通过{}指定,举例:cond1{条件判断}
    #注意#「条件判断节点」的别名建议统一以cond为前缀
    方角矩形 普通流程节点/子流程/状态图 不使用别名时的默认样式,也可以通过[]来强制指定,举例:node1[流程组]
    圆形 同页标志 结合别名,并通过(())指定,举例:node1((圆形节点)
    旗形 离页标志 结合别名,并通过>]指定,举例:page1>条件判断节点]
    #注意#「离页标志节点」的别名必须以page为前缀,否则样式会与「菱形」条件判断节点冲突
  4. 支持指定流程图方向:LR(从左到右)、RL(从右到左)、TB(从上到下)、BT(从下到上);

  5. 支持 FontAwesome 官网

顺序图 / 顺序图 / 泳道图

顺序图 / 顺序图 / 泳道图
sequenceDiagram
%% 设置显示消息的自动编号
autonumber

participant User as @人物角色
participant Client as 系统角色
participant Server as **重要系统角色**
participant Extend as --外部系统角色--

par 平行消息
	User ->> Client: 平行发送消息1
and
	User ->> Client: 平行发送消息2
and
  Client ->>+ Server: 平行发送消息3
  Server -->>- Client: 发送消息
end

%% 设置区域高亮
rect rgba(128, 128, 128, 0.3)
	Extend ->> Extend: 内部动作
end

Note left of Extend: 显示在外部系统<br>左侧备注说明
Note right of Extend: 显示在外部系统<br>右侧备注说明
Note over Client,Server: 跨对象备注说明
loop 循环
	Client ->>+ Extend: 发送消息A
	alt 抉择1
		Server -->> Client: 同步返回消息A1
	else 抉择2
		Server --X Client: 异步返回消息A2
	end
	opt 可选
		Extend ->>- Server: 发送消息X
	end
end
以上「顺序图」的画图脚本示例
sequenceDiagram
%% 设置显示消息的自动编号
autonumber

participant User as @人物角色
participant Client as 系统角色
participant Server as **重要系统角色**
participant Extend as --外部系统角色--

par 平行消息
	User ->> Client: 平行发送消息1
and
	User ->> Client: 平行发送消息2
and
  Client ->>+ Server: 平行发送消息3
  Server -->>- Client: 发送消息
end

%% 设置区域高亮
rect rgba(128, 128, 128, 0.3)
	Extend ->> Extend: 内部动作
end

Note left of Extend: 显示在外部系统<br>左侧备注说明
Note right of Extend: 显示在外部系统<br>右侧备注说明
Note over Client,Server: 跨对象备注说明
loop 循环组
	Client ->>+ Extend: 发送消息A
	alt 情景1
		Server -->> Client: 同步返回消息A1
	else 情景2
		Server --X Client: 异步返回消息A2
	end
	opt 可选
		Extend ->>- Server: 发送消息X
	end
end
说明
  1. 针对顺序图的不同图元应用,重绘不同的外观、形状;
  2. 针对 opt / alt / loop 标签设置不同的外观、标题位置。
  3. 建议使用实体别名,以提高画图脚本的复用度和可维护性;
  4. 支持三类消息线条:同步请求消息、异步请求消息、返回消息;
  5. 角色在标准的一类样式的基础上,增加三类扩展的样式,在输出HTML后应用 VLOOK™ 插件后渲染为不同的样式:
    • 人物角色:以at符号@开始的内容,如@人物角色
    • 重要系统角色:以两个星号**进行包裹的内容,如**后端支撑系统名称**
    • 外部系统角色:以两个减号--进行包裹的内容,如--外部系统名称--
  6. 支持对三类标签分组在输出HTML后应用 VLOOK™ 插件渲染为不同的样式:
    • loop...end:循环
    • opt...end:可选
    • alt..else...end:条件选择(alt = 情景1,else = 情景2)
  7. 支持备注说明。

类图

须mermaid V8.4及更新版本支持。

标准类图 (1)
classDiagram
classA <|-- classB : Inheritance
classC *-- classD : Composition
classE o-- classF : Aggregation
classG "*" <-- "1" classH : Association
classI "many" -- classJ : Link(Solid)
classK "1" ..> "1..n" classL : Dependency
classM <|.. classN : Realization
classO .. classP : Link(Dashed)

class classA~Class~{
    <<interface>>
    +public attribute
    -private attribute
    #protected attribute
    ~package attribute
    +public method()
    -private method()
    #protected method()
    ~package method()
}

class classC{
    <<enumeration>>
    RED
    BLUE
    GREEN
    WHITE
    BLACK
}
标准类图 (2)
classDiagram
classA <|-- classB : Inheritance
classC *-- classD : Composition
classE o-- classF : Aggregation
classG "*" <-- "1" classH : Association
classI "many" -- classJ : Link(Solid)
classK "1" ..> "1..n" classL : Dependency
classM <|.. classN : Realization
classO .. classP : Link(Dashed)

class classA{
    <<interface>>
    +public attribute
    -private attribute
    #protected attribute
    ~package attribute
    +public method()
    -private method()
    #protected method()
    ~package method()
}

class classC{
    <<enumeration>>
    RED
    BLUE
    GREEN
    WHITE
    BLACK
}
以上「类图」的画图脚本示例
classDiagram
classA <|-- classB : Inheritance
classC *-- classD : Composition
classE o-- classF : Aggregation
classG "*" <-- "1" classH : Association
classI "many" -- classJ : Link(Solid)
classK "1" ..> "1..n" classL : Dependency
classM <|.. classN : Realization
classO .. classP : Link(Dashed)

class classA~Class~{
    <<interface>>
    +public attribute
    -private attribute
    #protected attribute
    ~package attribute
    +public method()
    -private method()
    #protected method()
    ~package method()
}

class classC{
    <<enumeration>>
    RED
    BLUE
    GREEN
    WHITE
    BLACK
}

状态图

标准状态机图

环境要求
  • Typora macOS 版本丨0.9.9.30+ Windows 版本丨0.9.80+
  • mermaid Version丨8.4+
新版标准状态机图 (1)
stateDiagram
[*] --> 状态A
状态A --> 状态B : 状态转换说明
状态B --> 状态C : 状态转换说明
状态C --> 状态A : 状态转换说明
状态C --> [*]
以上「状态机图」的画图脚本示例
stateDiagram
[*] --> 状态A
状态A --> 状态B : 状态转换说明
状态B --> 状态C : 状态转换说明
状态C --> 状态A : 状态转换说明
状态C --> [*]
新版标准状态机图 (2)
stateDiagram
state fork_state <<fork>>

[*] --> 状态组1
状态组1 --> fork_state
fork_state --> 状态组2
fork_state --> 状态组3

note right of 状态组1
    【状态组1】右边的备注信息,
    内容支持换行。
end note
state 状态组1 {
    状态11 : 在此填写状态的描述内容
    [*] --> 状态11
    状态11 --> [*]
}

note left of 状态组2 : 【状态组2】左边的备注信息
state 状态组2 {
    [*] --> 状态21: 状态转换说明
    状态21 --> [*]
}

%% 可以编写注释(以两个英文百分号开头)
state 状态组3 {
    [*] --> 状态31
    状态31 --> [*]
    --
    [*] --> 大写【关闭】
    大写【关闭】 --> 大写【打开】 : 按一下 CapLock 键
    大写【打开】 --> 大写【关闭】 : 按一下 CapLock 键
}

state join_state <<join>>

状态组2 --> join_state
状态组3 --> join_state
join_state --> 状态4
状态4 --> [*]
以上「状态机图」的画图脚本示例
​```mermaid
stateDiagram
state fork_state <<fork>>

[*] --> 状态组1
状态组1 --> fork_state
fork_state --> 状态组2
fork_state --> 状态组3

note right of 状态组1
    【状态组1】右边的备注信息,
    内容支持换行。
end note
state 状态组1 {
    状态11 : 在此填写状态的描述内容
    [*] --> 状态11
    状态11 --> [*]
}

note left of 状态组2 : 【状态组2】左边的备注信息
state 状态组2 {
    [*] --> 状态21: 状态转换说明
    状态21 --> [*]
}

%% 可以编写注释(以两个英文百分号开头)
state 状态组3 {
    [*] --> 状态31
    状态31 --> [*]
    --
    [*] --> 大写【关闭】
    大写【关闭】 --> 大写【打开】 : 按一下 CapLock 键
    大写【打开】 --> 大写【关闭】 : 按一下 CapLock 键
}

state join_state <<join>>

状态组2 --> join_state
状态组3 --> join_state
join_state --> 状态4
状态4 --> [*]

### 旧版状态图

###### 说明

1. 该样式的状态图是借用**流程图**脚本实现,是mermaid未支持[标准状态图](#标准状态机图)时的变通方案;
2. 针对该类状态图及不同图元的应用,重绘不同的外观、形状;
3. 特定节点命名规范:
   - `INIT`:初始状态
   - `FINAL`:最终状态
4. 建议使用`方角矩形`节点来表示状态;
5. 根据情况适当使用别名(如:A、B、C 等,可自由定义);
6. 可适当结合`菱形`节点用于表示**分支**和**聚合**。

###### 旧版状态机图(兼容性较高)

​```mermaid
graph LR
%% 流程图走方说明
%% LR:从左到图,RL:从右到左,TB:从上到下,BT:从下到上

INIT(( )) -->	|初始|A[状态A]
A --> |复杂变更|fork1(( ))
fork1(( )) --> |变更条件说明|B[状态B]
B --> |变更条件说明|C[状态C]
fork1{ } -.-> |非正常/次要变更条件说明|C
C --> FINAL
fork1{ } -.-> |非正常/次要变更条件说明|D[状态D]
D --> FINAL
FINAL(( ))
以上「状态机图」的画图脚本示例
​```mermaid
graph LR
%% 流程图走方说明
%% LR:从左到图,RL:从右到左,TB:从上到下,BT:从下到上

INIT(( )) --> |初始|A[状态A]
A --> |复杂变更|fork1(( ))
fork1(( )) --> |变更条件说明|B[状态B]
B --> |变更条件说明|C[状态C]
fork1{ } -.-> |非正常/次要变更条件说明|C
C --> FINAL
fork1{ } -.-> |非正常/次要变更条件说明|D[状态D]
D --> FINAL
FINAL(( ))

## 甘特图

###### 甘特图

​```mermaid
gantt
dateFormat  YYYY-MM-DD
title 这里显示甘特图标题

%% this is a comment

section 区块A
已完成的普通任务:done, des1, 2014-01-06, 2014-01-08
执行中的普通任务:active, des2, 2014-01-09, 3d
未来的任务:des3, after des2, 2d
未来的任务2:des4, after des3, 2d

section 区块B
已完成的关键路径任务:crit, done, 2014-01-06, 24h
已完成的关键路径任务2:crit, done, after des1, 2d

section 区块C
执行中的关键路径任务:crit, active, 3d
未来的关键路径任务:crit, 2d
![以上「甘特图」的画图脚本示例]
​```mermaid
gantt
dateFormat  YYYY-MM-DD
title 这里显示甘特图标题

%% this is a comment

section 区块A
已完成的任务:done, des1, 2014-01-06, 2014-01-08
执行中的任务:active, des2, 2014-01-09, 3d
未来的任务:des3, after des2, 5d
未来的任务2:des4, after des3, 5d

section 区块B
已完成的关键路径任务:crit, done, 2014-01-06, 24h
已完成的关键路径任务2:crit, done, after des1, 2d

section 区块C
执行中的关键路径任务:crit, active, 3d
未来的关键路径任务:crit, 5d

## 饼图

###### ![Q3 2019 中国线上智能手机市场主要品牌市场份额]"数据来自:互联网"

​```mermaid
pie title Q3 2019 中国线上智能手机市场主要品牌市场份额
"华为" : 26
"荣耀" : 20
"小米" : 14
"VIVO" : 10
"Apple" : 9
"OPPO" : 5
"其他" : 16
以上「饼图」的画图脚本示例
​```mermaid
pie title Q3 2019 中国线上智能手机市场主要品牌市场份额
"华为" : 26
"荣耀" : 20
"小米" : 14
"VIVO" : 10
"Apple" : 9
"OPPO" : 5
"其他" : 16

## 实体关系图 / ER图 <sup>`beta`</sup>

​```mermaid
erDiagram
    CUSTOMER ||--o{ ORDER : places
    ORDER ||--|{ LINE-ITEM : contains
    CUSTOMER }|..|{ DELIVERY-ADDRESS : uses 

用户体验地图 / 用户旅程地图 beta

journey
    title My working day
    section Go to work
      Make tea: 5: Me
      Go upstairs: 3: Me
      Do work: 1: Me, Cat
    section Go home
      Go downstairs: 5: Me
      Sit down: 5: Me

备选方案

#注意#(从 VLOOK 9.2 版本开始不再支持备选方案)

flowchart.js (流程图)

flowchart.js 基于 SVG 的流程图插件,它仅需几行代码即可在 Web 上完成流程图的构建。可以从文字表述中画出简单的 SVG 流程图,也可以画出彩色的图表。详见 flowchart.js 官网

JS Sequence Diagrams (顺序图)

JS sequence diagrams 是一个方便建立 UML 的顺序图(序列图 or 循序图)在线工具,使用简单。详见 JS Sequence Diagrams 官网

######The End

VLOOK™
让你的 Markdown 有了新看法
──
快速参考手册
#最新版本|V9.23#idle

MΛX°孟兆
COPYRIGHT © 2016-2020. MAX°DESIGN.

[TOC]

VLOOK™ 是什么

#最新版本|V9.23#msg #适用编辑器|Typora#notice #开源协议|MIT# #开发语言|JavaScript/HTML/CSS#spare #官网|https://github.com/madmaxchow/VLOOK#tips

VLOOK™ 是针对由 Typora[^Typora](目前最好的跨平台 Markdown 编辑器,没有之一)导出的 HTML 文件进行增强的插件。

VLOOK™ 也许是目前最好的 Markdown 增强插件之一,也是==开源中国(OSChina.net)推荐的国产开源产品==。

VLOOK™ 属于开源软件,遵从 **MIT 许可证**。

[+] VLOOK™ 许可协议

MIT许可证

版权所有 (c) 2018-2020 MAX°DESIGN | Max Chow

在此授予任何获得此软件和相关文档文件(“软件”)副本的人免费许可,以无限制地处理本软件,包括但不限于使用,复制,修改,合并,发布,分发,再授权和/或出售本软件的副本,并允许本软件的授予人员遵从以下情况:

上述版权声明和本许可声明应包含在本软件的所有副本或重要部分中。

本软件按“原样”提供,不提供任何以表达或暗示,包括但不限于销售,适用于特定用途和不侵权的保证。在任何情况下,作者或版权所有人不对因软件或软件的使用或其他事宜产生的任何索赔,损害或其他责任(无论是在合同,侵权或其他方面的诉讼中)负责。

[+] Markdown 是什么?

  • 2004年,John Gruber 创造了 Markdown,一种专门针对网络写作的文本标记语言。使用 Markdown,你只需在写作过程中插入少量的标记符号,就能很轻松地进行排版(例如设置标题、加粗、列表、引用等)。
  • Markdown文档以纯文本格式存储,这意味着,它们可以用几乎任一种文本编辑器打开。同时,又能通过 Markdown 编辑器导出为带排版的富文本文档、HTML 网页等等。==纯粹、简洁、易用、灵活==,都是人们喜欢 Markdown 的原因。
  • 目前 Markdown 的标准化项目是 CommonMark

[+] 60 秒学会、10 分钟深入学习 Markdown 语法:

  1. 标准化 CommonMark 语法参考:60秒学会 Markdown 语法10 分钟深入学习 Markdown
  2. GitHub 采用 Flavored Markdown 的语法参考:Typora 目前采用该标准 详细

[^Typora]: Typora 是非常棒的跨平台的 Markdown 编辑器,支持直接预览与编辑,更详细的特性详见官网

适用场景

如果你也有以下一个或多个需求或痛点,就可以放心地尝试基于 Markdown 的解决方案(如 Typora + VLOOK)进行文档的编辑、发布、管理:

  • 团队或项目的文档须==统一模板与输出==,并能随时切换不同模板
  • 只关注文档内容的撰写,==排版==这种工作希望能==自动化==完成
  • ==以网络作为主要的发布渠道==,主要发布为 HTML 格式,同时能发布为 PDF 等其它常用格式
  • ==减少==在文档(如 Word)、制图(如 Visio)等软件工具方面的==购买支出==
  • 需要支持==跨平台==(Windows / macOS / Linux 等)进行文档的编辑的与输出的软件工具
  • 文档排版、交互、个性化主题等功能方面,具备可持续升级的能力和开放性

特性清单

VLOOK™ 充分挖掘和扩展了 Markdown 和 Typora 的语法和功能,并结合现代网络化的文档编辑和出版中涉及的文档的 格式排版文档导航演示辅助内容交互 等方面的需求,为你提供基于 Markdown 的文档编辑、文档发布、文档阅读者提供 一致简洁友好 的体验。

#提示#tips 你正在浏览在这个网页就是由 Typora 编辑并植入 VLOOK™ 插件所生成,并应用了 VLOOK™ 的所有的特性

![VLOOK™ 特性清单]”环境要求:VLOOK™ V9.7+,Typora mac版 V0.9.9.31+ / Win版 V0.9.83+”
VLOOK™ 的特性及简介
==一、排版增强==
封面、封底
配合主题样式,让你用 Markdown 写的文档也能焕发专业气质
多主题样式
让你的文档尽显个性,同时提供主题定制服务
标题、插图、表格、表格行支持自动编号
“0”配置,跟 Word 说 ByeBye 吧~
自动生成插图、表格、代码块、音/视频的题注
OMG!配合插图、表格、代码块、音/视频的自动编号,高效高颜值!还有独特的双题注~
表格单元格合并
这个是用 Markdown 人的真痛点,在这时为你提供了优雅的解决方法
表格列格式化
Markdown 的表格也能快速设置列的格式(如加粗、高亮、斜体、下划线),同样为你提供了优雅的解决方法
彩虹标签
可自定义多个配色的标签、双标签,让你的 Markdown 文档排版更专业、更标准化
[mermaid 样式优化](#mermaid 样式优化)
全面深度优化 mermaid 图表,并提供补丁修正其跨平台的兼容性问题
图片反色、增加边缘空白
可指定在 Dark 模式时反色,还能增加边缘空白,让图片的呈现更和谐、阅读体验更佳
统一多级列表自动编号
将多级有序、无序列表的编号进行了统一,以更聚焦内容的结构化
任务列表支持自动编号
让任务列表和多级列表的自动编号两者兼得
==二、文档导航==
大纲导航
最为熟悉和常用的文档导航方式,支持多级章节折叠
(适合于全局快速定位到文档内的目标章节)
逐章导航
在长文档中特别好用,随时眯一眼就知道当前章节、前 / 后章节是什么了
(适合于在多章节间频繁切换,浏览相近章节的内容)
逐段导航
这个很 GEEK,可以通过键盘逐段进行浏览,习惯用 VI / VIM 的人应该会欢呼!
(适合于内容审核、讲解时,让演讲人与观众共同聚焦到同一段上)
插图导航
让你快速在快速浏览文档的所有插图,并能直接跳到文档中对应的位置
==三、演示辅助==
聚光灯
太COOL了!在投影时可以让大家快速聚焦在关键内容上了
表格十字光标
方便你与大家讨论长表格、大表格时,快速聚焦指定单元格,及对应的行和列
在新标签打开插图、表格、代码块
在长文档中的来回翻页查看插图、表格、代码示例是很崩溃的事,现在你可以让它们在浏览器的不同标签中显示了
==四、内容互动==
表格行分组
程序员、产品经理呼声最高的表格增强之一,从此你的表格就可以轻松实现分组和多级缩进了
支持音频、视频
你的 Markdown 文档从此可以看视频、听音频了,音频还支持迷你模式,应用的潜力等你来发挥~
代码块增强
在这你会发现连闷骚的代码都透着动感,高亮当行、复制~
引用内容可设置为折叠
引用内容很长很多?现在可以指定是否默认收起,读者点击才展示引用内容……在 VLOOK™ 的加持下,这里都不是事
长内容自动折叠
长图、长表格、长代码会占用太多屏幕空间?现在可以统统自动折叠,静待你的二维展开指令
文档内容检查与优化
文档中的页内链接、图片链接失效了,现在 VLOOK™ 会悄悄告诉你的
更友好的脚注
用 Markdown 也可以像 Kindle 那样以弹窗方式来看脚注
==五、视觉与交互==
[Dark 模式](#Dark 模式)
这个不用多说了,懂的人都会喜欢。也可手动切换回标准的 Light 模式
字体风格选择
AMAZING! 不同的字体风格为你的文档带来不同的调性~
更美观的公式
让你的各种公式长得与 VLOOK™ 的不同主题更搭
打印样式适配
使用 VLOOK™ 提供的打印功能,确保文档样式适合商务办公场景下的打印输出
快捷键操作
支持键盘快捷键操作,又可以再装个逼了~
跨平台支持
能自适应在 PC 、平板、手机上进行浏览
自动识别链接类型
自动识别对文档的内部链接、外部链接,鼠标在链接上悬停时通过不同的角标图示进行区分
七语种界面
界面提示说明、题注前缀等内容,均支持:简/繁/英/法/俄/日/韩(依赖于浏览器的当前语言设置)

特性介绍

排版增强

有了 VLOOK™ 主题及插件的支持,让你对 Markdown 编辑器(暂只支持 Typora)的自动化排版能力有了全新的理解。

多主题样式

VLOOK™ 已为你内置了多套原创、独具风格的主题样式[^主题样式],能满足日常大多不同的应用场景和视觉偏好:

内置高颜值实用的主题

[+] 我要怎样才能使用这些内置的主题?

下载并添加主题文件(vlook-.css)到 Typora 主题目录后,在导出 HTML 前通过 Typora 的「主题」菜单选择以「VLOOK」为前缀的主题,如:*Vlook hope

── 更多使用指引详见《如何使用

#私人定制#目前 VLOOK™ 项目也现已开放了主题的 私人定制 服务 #微信|MaxChow#tips,定制样品示例如下:

私人定制主题

[^主题样式]: 可以根据源码目录下 LESS 文件为样例进行自定义扩展,访问 VLOOK™ 的 github 主页了解更多。

封面、封底

应用了 VLOOK™ 的主题后,即可通过 Markdown 的标准语法(须按 VLOOK™ 约定的使用规范)即可激活对应主题的封面、封底。

[+] 这样就能激活封面!

在文档的最开始输入一个 6 级标题###### 这是封面标题即可激活,同时已内置对特定类型信息的自动排版,具体如下:

[+] 标题

  • 默认格式就是标题格式,直接输入就可以了;
  • 可结合 HTML 的上标、下标方式进行大标题、小标题的延伸应用:
    • 上标:<sup>上标内容</sup>
    • 下标:<sub>下标内容</sub>

[+] 文档类型、密级

可使用 VLOOK™ 的双标签风格写法来实现,举例:

  • `#文档密级|对外公开#tips`
  • `#文档密级|内部公开#notice`
  • `#文档密级|机密资料#caution`

[+] 作者

使用 Markdown 的「粗体」格式标记出「作者信息」即可(会自动添加前缀「by」、加粗),举例:**我是作者**

[+] 版权信息

使用 Markdown 的「斜体」格式标记出「版权信息」即可(会自动缩小字号、加粗),举例:*(C)2020. 版权所有*

以下是本文档封面的完整 Markdown 语法示例内容:

###### <sup>VLOOK™</sup><br>让你的 Markdown 有了新看法<br>──<br><sub>快速参考手册</sub><br><br><br><br>**MAX丨孟兆**<br>*COPYRIGHT © 2016-2020. MAX°DESIGN.*

#提示#tips 封面内如何换行? 可直接输入 HTML 的换行标签<br>即可,或直接使用快捷键 Shift + ENTER ↵

[+] 这样就能激活封底!

在文档的最末处输入一个 6 级标题###### 这是封底结语即可激活,同时已内置对特定类型信息的自动排版。

以下是本文档封底的完整 Markdown 语法示例内容:

###### The End

~ SO EASY!

标题、插图、表格、表格行自动编号

如果你使用过 Word 的标题、图表的自动编码功能,就会惊喜地发现,基于 Markdown 也能做到,甚至能做得更好~
既不需要进行额外的设置和语法支持,甚至还能对表格行进行自动行号编号,一起来看看吧。

[+] 标题自动编号

所有 VLOOK™ 的主题都会自动对 1 ~ 5级 标题进行自动编号;

编号的格式就是你在本文各级章节标题所看到的那样;

因为6级 标题在 VLOOK™ 中应用于封面和封底、段落小标题的排版等,所以不在自动编号范围内。

[+] 插图自动编号

支持对文档内所有的插图,包括图片、mermaid 图表进行统一的自动编号,编号格式为:图 XX

正如你在前面看到的那些介绍内置主题的图片那样。

[+] 表格、表格行自动编号

支持对文档内所有表格进行统一的自动编号,编号格式为:表 XX

要激活表格行的自动编号,须在表格前添加任意层级的标题,或为有序 / 无序列表下的缩进表格,如:###### 这是一个表格

表格前添加 6 级标题会激活表格行的自动编号,效果如下
列1 列2 列3 列4
第一行 左对齐(长内容) 居中对齐 右对齐(长内容)
第二行(长内容) 左对齐 居中对齐(长内容) 右对齐
  • 有序 / 无序列表下的缩进表格,会激活表格行的自动编号,效果如下:

    列1 列2 列3 列4
    第一行 左对齐(长内容) 居中对齐 右对齐(长内容)
    第二行(长内容) 左对齐 居中对齐(长内容) 右对齐

#提示#tips听说你还想给插图、表格添加题注?好消息是 VLOOK™ 也支持,接着看就能又甩你一个新技能~

自动生成插图、表格、代码块、音/视频的题注

你只需要按 GFM 添加图片的 Markdown 语法,VLOOK™ 就会自动为你的图片添加图注。
如果你要为表格、mermaid 图表,甚至还要同时支持两个题注,这些都可以使用 VLOOK™ 扩展的类似添加图片的语法就能轻松实现~

[+] 这样做,你就能为图片自动生成题注

以 GFM 添加图片的 Markdown 语法为基础:![图片标题](图片URL "可选子标题")

  • 图片标题:即为默认题注,如:![这是图片的默认题注](图片URL)
  • 可选子标题:若填写了可选子标题,该可选子标题就会自动生成为第 2 题注,如:![这是图片的默认题注](这是图片的第2题注)

#注意#以上语法中的「可选子标题」与「图片URL」间须以英文空格 SPACE 进行分隔

[+] 这样做,也能为表格、mermaid 图表、代码块添加题注

  • 懒人方案:
    • 在表格、mermaid 图表、代码块前直接编写题注内容;
    • 然后将内容设置为六级标题(例如:###### 这条是表格题注),同时该六级标题内容在生成题注后,不会被隐藏。
  • 扩展语法、双题注方案:
    • 在表格、mermaid 图表、代码块前增加题注描述,使用语法是 VLOOK™ 扩展 GFM 的添加图片的 Markdown 语法;
    • 语法:``![默认题注]”第2题注”`,其中的「第 2 题注」内容为可选;
    • 该语法的所有内容由 VLOOK™ 转换后被隐藏,若要保留原始标题内容,可另起一行进行描述。

有关 表格、mermaid 图表 的题注效果效果可以继续看下面表格单元格合并的表格样例

表格单元格合并

表格是文档中最多见的元素,虽然 GFM 扩展了 Markdown 的语法实现了对表格的支持,但对排版上的支持还是比较弱。
目前 Markdown 粉们呼声最多的就是单元格合并了~

现在 VLOOK™ 已为你带了简洁、优雅的单元格跨行、跨列合并的解决方案:

[+] 跨列合并(横向)语法

单元格内容为两个连续的左侧尖括号<<进行标识,该单元格将会与左邻的单元格进行合并,以此类推。

#注意#旧语法为两个连续的英文句号==,目前已废弃,不建议使用!

[+] 跨行合并(纵向)语法

单元格内容为两个连续的次方符号^^进行标识,该单元格将会与上方的单元格进行合并,同时还支持表头的跨行合并。

#注意#旧语法为两个连续的英文句号..,目前已废弃,不建议使用!

![示例一:单元格并列合并、行合并]”注:须使用最新版的 Typora 和 VLOOK”

| 普通列头 | #标签|测试#列合并(2列) | << | 普通列头 | 列合并(3列) | << | << |
| —————– | ————————– | ———————– | ———- | ————- | ———- | —————— |
| 行合并(3行) | 普通单元格 | 普通单元格 | 普通单元格 | 普通单元格 | 普通单元格 | 跨行(全合并) |
| ^^ | 行合并(2行)#标签|测试# | 列合并(4列) | << | << | << | ^^ |
| ^^ | ^^ | 普通单元格 | 普通单元格 | 普通单元格 | 普通单元格 | ^^ |
| 普通单元格 | 行合并(3行) | 普通单元格 | 普通单元格 | 普通单元格 | 普通单元格 | ^^ |
| 普通单元格 | ^^ | #标签|测试#普通单元格 | 普通单元格 | 普通单元格 | 普通单元格 | ^^ |
| 普通单元格 | ^^ | 普通单元格 | 普通单元格 | 普通单元格 | 普通单元格 | ^^ |

示例二:表头跨行合并1
列头行合并(2行) 列头列合并(2列) << 列头行合并(2行) 列头列合并(3列) << <<
^^ 二级列头 二级列头 ^^ 二级列头 二级列头 二级列头
普通单元格 普通单元格 普通单元格 普通单元格 普通单元格 普通单元格 普通单元格
普通单元格 普通单元格 普通单元格 普通单元格 普通单元格 普通单元格 普通单元格
示例三:表头跨行合并2
列头行合并(3行) 列头行合并(3行) 列头列合并(3列) << << 普通列头 普通列头
^^ ^^ 二级列头1 二级列头2 二级列头3 ^^ ^^
^^ ^^ 三级列头1 三级列头2 三级列头3 ^^ ^^
普通单元格 普通单元格 普通单元格 普通单元格 普通单元格 普通单元格 普通单元格

#注意#如果你还需要对表格的列格式进行设置(如整列加粗、斜体等),VLOOK™ 也提供了同样好的支持,详见以下的表格列格式化

表格列格式化

表格是文档中最多见的元素,虽然 GFM 扩展了 Markdown 的语法实现了对表格的支持,但对排版上的支持还是比较弱。

VLOOK™ 除了为你带来单元格合并的能力外,还支持设置表格整列格式的能力~

表格列普通格式化

只须在表头按以标准的 Markdown 或 GFM 的格式设置语法设置对应的格式即可实现整列格式化。

目前支持的格式设置语法:**加粗***斜体*~~删除线~~==高亮==<u>下划线</u>

表格列普通格式化示例
加粗 #标签#斜体 下划线 ==高亮== 删除线
单元格 单元格 单元格 单元格#标签#单元格 单元格`#标签组
单元格 单元格 单元格 单元格内有加粗内容 单元格内有加粗内容
单元格 单元格 单元格 单元格内有行内代码内容 单元格内有行内代码内容
表格列普通格式化(嵌套)示例
==高亮+下划线== 加粗+斜体+下划线 ==加粗+高亮== 删除线+加粗列
单元格 单元格 单元格#标签#单元格 单元格`#标签组
单元格 单元格 单元格内有加粗内容 单元格内有加粗内容
单元格 单元格 单元格内有行内代码内容 单元格内有行内代码内容

表格列增强格式化

通过对列头以 GFM 标准语法为基础进行扩展,以及对不同的对齐方式进行约定处理,以实现对整列的格式。

  • 带复选框的列:表格列关的内容以[(空格)](空格)开头默认该列单元格内容前增加复选框,样式说明如下:
    • 默认为「未选择」样式;
    • 若内容以[x]开头时,为「已选择」样式;
    • 若内容前添加[-]开头时,为「不确定选择」样式。
    复选框样式 [ ] 带复选框的列 说明
    未选择 默认样式
    已选择 [x]
    不确定选择 [-]
    当值 ≥ 0 时
  • 数值格式列:表格列设置为「右对齐」,则针对数字内容强制设置为「数值」格式,数值格式说明如下:
    • 分隔符:千位符

    • 负数:变色

    • 字体:等宽字体

    • 小数:位数不调整

    数值列(非右对齐) 数值列(右对齐)
    123 123
    1234 -1234
    123456789.00 123456789.00
    1234567^.89^ 1234567^.89^

彩虹标签

VLOOK™ 基于 Markdown 的行内代码标记` ` ,扩展语法来支持 标签(tag) 功能,并能同时支持 单标签双标签(嵌套标签)

单标签风格

  • 语法:

    • 使用行内代码语法``
    • 内容以#开始,并以#结束,如:`#标签#`
  • 支持通过在结束的#后添加指定不同的类型后缀标识(不指定时默认为 caution),实现不同类型的标签会以不同的样式进行渲染:

    ![单标签示例]”(不指定时默认为 caution)”

    后缀标识 举例 应用场景建议 色调 渲染效果
    msg `#标签#msg` 信息、资讯、公告 #标签#msg
    tips `#标签#tips` 提示、备忘、参考、新增 绿 #标签#tips
    notice `#标签#notice` 提醒、注意、关注、优化、修复 #标签#notice
    caution `#标签#caution` 警告、危险、关键事项、删除 #标签#caution
    spare `#标签#spare` 延伸、扩展、保留、备用 #标签#spare
    idle `#标签#idle` 无效、暂缓、停用、结束 #标签#idle

双标签风格

  • 支持嵌套式的双标签,满足二元结构内容的应用需要,举例如下:

    • #版本号|V1.0.2#msg
    • #变更 X 的取值|1234.00#tips
    • #优先级|中#notice
    • #优先级|高#
  • 语法:在「单标签」语法的基础上,以英文竖线符号|作为分隔符,如`#标签组|标签#`

    ![双标签(嵌套标签)示例]”(不指定时默认为 caution)”

    后缀标识 举例 应用场景建议 色调 渲染效果
    msg `` `#标签组 标签#msg` `` 信息、资讯、公告
    tips `` `#标签组 标签#tips` `` 提示、备忘、参考、新增 绿
    notice `` `#标签组 标签#notice` `` 提醒、注意、关注、优化、修复
    caution `` `#标签组 标签#caution` `` 警告、危险、关键事项、删除
    spare `` `#标签组 标签#spare` `` 延伸、扩展、保留、备用
    idle `` `#标签组 标签#idle` `` 无效、暂缓、停用、结束

mermaid 样式优化

VLOOK™ 针对比较受关注的 mermaid 图表提供了样式的统一和优化,并提供跨平台跨浏览器的兼容性补丁。

[+] 统一和优化样式

支持 mermaid 的 饼图、流程图、状态图、顺序图、类图、甘特图,同时还能自动适配 [Dark 模式](#Dark 模式)。

除了样式优化外,还对书写规范进行了统一,效果比其官网的要好上许多许多~

  • 基于流程图衍生出状态机图;
  • 针对顺序图,支持不同角色类型(人、系统、重要系统、外部系统),重绘不同的外观样式;
  • 针对顺序图的 #opt#spare #alt / else# #loop#notice 标签优化不同的外观样式,以及自动翻译为当前浏览器的语言。

[+] 跨平台跨浏览器的兼容性补丁

操作系统涉及 Windows、macOS、Linux,分辨率涉及到普通和高清,浏览器涉及主流的 Chrome / Firefox / Edge。

mermaid 的图表在以上复杂情况下的一致性还是做得不够到位,所以 VLOOK™ 提供了一个非官方的兼容补丁,为大家提供一个更好的浏览体验

mermaid 的流程图

![流程图]”(以上的「分支流程」内容由下图进行接续)”

graph LR
START(开始) --> node1(普通节点)
subgraph 子图
	node1 --> |情况1|groud1[流程组节点]
  node1 --> |情况2|A1((A))
end

%% this is a comment

groud1 ==> |重要分支|cond1{条件判断}
cond1 --> |是|END
cond1 -.-> |否|page2>分支流程]
A2((A)) --> END
END(结束)

![分支流程(接续上图)]

graph LR
page2>分支流程] --> node2(普通节点)
node2 --> END
END(结束)
mermaid 的状态图

![由 mermaid 流程图语法衍生的状态图]

graph LR
%% 流程图走方说明
%% LR:从左到图,RL:从右到左,TB:从上到下,BT:从下到上

INIT(( )) -->	|初始|A[状态A]
A --> |复杂变更|fork1(( ))
fork1(( )) --> |变更条件说明|B[状态B]
B --> |变更条件说明|C[状态C]
fork1{ } -.-> |非正常/次要变更条件说明|C
C --> FINAL
fork1{ } -.-> |非正常/次要变更条件说明|D[状态D]
D --> FINAL
FINAL(( ))
mermaid 的顺序图

![多种不同角色的顺序图,更清晰、更友好]

sequenceDiagram
%% 设置显示消息的自动编号
autonumber

participant User as @人物角色
participant Client as 系统角色
participant Server as **重要系统角色**
participant Extend as --外部系统角色--

par 平行消息
	User ->> Client: 平行发送消息1
and
	User ->> Client: 平行发送消息2
and
  Client ->>+ Server: 平行发送消息3
  Server -->>- Client: 发送消息
end

%% 设置区域高亮
rect rgba(128, 128, 128, 0.3)
	Extend ->> Extend: 内部动作
end

Note left of Extend: 显示在外部系统<br>左侧备注说明
Note right of Extend: 显示在外部系统<br>右侧备注说明
Note over Client,Server: 跨对象备注说明
loop 循环
	Client ->>+ Extend: 发送消息A
	alt 抉择1
		Server -->> Client: 同步返回消息A1
	else 抉择2
		Server --X Client: 异步返回消息A2
	end
	opt 可选
		Extend ->>- Server: 发送消息X
	end
end

#参考#tips更多脚本化图表样式,以及结合 VLOOK™ 相关的脚本编写规范内容详见《脚本化图表 for Markdown》。

图片反色、增加边缘空白

应用了 VLOOK™ 主题的文档,针对图片提供了更加精细的排版特性。

指定图片在 Dark 模式时反色显示
  • 图片默认在 Dark 模式时按原始颜色显示,对于一些透明底的 PNG 图片(如界面线框图),可指定在 Dark 模式时以反色显示以获得更好的显示效果;
  • 对需要在 Dark 模式中以反色显示的图片,可在图片 URL 增加启用 Dark 模式反色标记invert=in-dark,举例如下:

图片默认样式(不指定在 Dark 模式时反色)

指定切换至 Dark 模式后反色后会长这样(指定了在 Dark 模式时反色)

指定图片添加边缘空白
  • 对需要添加边缘空白的图片,可在图片 URL 增加启用边缘空白的参数padding=true
  • 举例: ![图片题注](xxxxx.png?padding=true)
  • 以上两图图片已开启边缘空白,以适合图片内容过于贴边,无留白的情况。

[+] 图片 URL 参数语法说明

  • 图片 URL 无参数时:先在 URL 后添加英文问号?后,再添加需要的 URL 参数: ![图片题注](xxxxx.png?invert=in-dark)
  • 图片 URL 已有参数时:多个参数间用英文特殊符号&进行分隔: ![图片题注](xxxxx.png?invert=in-dark&padding=true)

统一多级列表编号

对所有有序无序的多级列表编号进行了统一以有序编号为主,无序编号为辅,简化多级内容的编写。

[+] 列表分级编号样式效果

  • 一级列表内容

  • 一级列表内容

    • 二级列表内容
      • 三级列表内容
        • 四级列表内容
          • 五级列表内容
            • 六级列表内容
  • 三级列表内容

Markdown 原始内容参考如下:

- 一级列表内容
   - 二级列表内容
     - 三级列表内容
       - 四级列表内容
         - 五级列表内容
           - 六级列表内容
1. 一级列表内容
   + 二级列表内容
     - 三级列表内容

任务列表支持自动编号

GFM 标准的任务列表(to-do)默认会取消其列表编号。
VLOOK™ 主题会保持任务列表特性基础上,恢复列表编号的显示,并与上面统一多级列表编号保持一致。

举例如下:

  • 这是一级任务列表项
    • 这是二级任务列表项
    • 这是「已完成」的二级任务列表项
      • 这是三级任务列表项
        • 这是四级任务列表项
          • 这是五级任务列表项
            • 这是六级任务列表项
    • 这是二级任务列表项
  • 这是一级任务列表项

文档导航

VLOOK™ 提供了对文档章节、插图提供了多种形式的导航和快速定位的工具,全面改善和提高发布的 HTML 文件的浏览体验和效率。
敬请你根据需要和喜好随时、轻松享用~

![文档导航工具及适用场景]

导航工具 适用场景
大纲导航 适用于目标明确,跨多个章节的快速定位
逐章导航 适用于前后章节相关度高,按章节顺序一章一章进行浏览
逐段导航 适用于文档评审或演示,按段落一段一段进行聚焦式浏览
插图导航 适用于按图索骥,通过浏览文档中的插图(图片、mermaid 图表)来直接跳到文档中对应的位置

大纲导航

在封面时,点击左上角的大纲按钮打开大纲导航面板。不在封面时,会自动贴在文档左侧固定显示大纲导航面板。
支持对章节进行折叠 / 展开。

#注意#编写 Markdown 文档时,须在封面后添加目录标记[TOC]才能在导出的 HTML 中生成大纲面板。

逐章导航

进入文档正文区后,会自动在顶部显示逐章导航条,在封面时会自动收起隐藏,支持对 1~5 级章节进行逐章浏览。
从左到右分别为:前一章节当前章节后一章节,正如你现在看到顶部的导航栏那样。
鼠标点击对应的章节直接跳转到对应的章节开始位置,也可通过左 / 右方向键进行操作。

#注意#编写 Markdown 文档时,须在封面后添加目录标记[TOC]才能在导出的 HTML 中生成逐章导航面板。

逐段导航

在进行文档评审或演示时,可以激活逐段导航,对单段内容进行聚焦。
通过鼠标双击文档任意段落激活逐段导航模式,并通过快捷键进行上 / 下改变当前聚焦的段落。

![逐段导航的浏览操作方式(致敬 VI / VIM)]

快捷键 功能
J 下一个段落
K 上一个段落
H 往前跳十个段落
L 往后跳十个段落

插图导航

  • 点击任意插图可直接启动插图导航,或点击工具栏上的插图导航图标启动;
  • 点击插图导航内的插图,能直接跳转到文档中对应的位置。

[^mermaid]: mermaid 是一个用于画流程图、状态图、顺序图、甘特图的库,使用 JS 进行本地渲染,广泛集成于许多 Markdown 编辑器中。详见 mermaid官网,或 VLOOK™ 的示例文档《脚本化图表 for Markdown
[^flowchart.js]: flowchart.js 基于 SVG 的流程图插件,它仅需几行代码即可在 Web 上完成流程图的构建。可以从文字表述中画出简单的 SVG 流程图,也可以画出彩色的图表。详见 flowchart.js 官网,或 VLOOK™ 的示例文档《脚本化图表 for Markdown》。
[^JS Sequence Diagrams]: JS sequence diagrams 是一个方便建立UML的顺序图(序列图or循序图)在线工具,使用简单。详见 JS Sequence Diagrams 官网,或 VLOOK™ 的示例文档《脚本化图表 for Markdown》。

[+] 支持的插图类型

  • 浏览器支持的所有图片(如:jpg / png / gif / bmp 等)
  • 脚本化图表(mermaid[^mermaid],从V9.0开始移除对 flowchart.js[^flowchart.js]、JS Sequence Diagrams[^JS Sequence Diagrams]的支持)
这是长图片示例:

普通的图片示例(长图会自动折叠)

演示辅助

VLOOK™ 独创性地为 Markdown 导出的 HTML 提供了强大的演示辅助工具,让面向 Markdown 的 Typora + VLOOK 成为更具生产力的交互式文档出版工具。

非常适合现场和远程的演示辅助工具,敬请为你的 Markdown 开启 Turbo 模式~

![演示辅助工具及适用场景]

演示辅助工具 适用场景
聚光灯 对局部内容进行聚焦,如:插图、多个段落内容
表格十字光柱 针对表格内容,特别是行 / 列关联性强的表格,快速关联任意单元格的横向、纵向单元格序列
新标签打开插图、表格、代码块 针对须频繁在多个插图、表格、代码块间进行切换时使用,大大减少不必要的文档内跳转

聚光灯

在进行文档评审或演示时,可以通过激活聚光灯来让观众聚焦于文档的特定区域和内容。

通过工具栏上的「聚光灯」按钮打开 / 关闭,也可通过快捷键 S 进行操作,同时还可以通过按下 ⇧ Shift 键调节大小。

#小提示#tips聚光灯在新标签打开的页面中也可以使用喔~

表格十字光标

鼠标点击表格上的任意单元格后,会自动显示十字光标,高亮其横向、纵向关联对应的单元格序。

查看示例效果

#小提示#tips表格十字光标在新标签打开的页面中也可以使用喔~

在新标签打开插图、表格、代码块

支持在新标签中打开文档中的 插图表格代码块,鼠标悬念在这些文档内容上时会在左上角显示「在新标签打开」的按钮,点击即可。

查看示例效果

内容互动

得益于成熟的 Web 浏览器、HTML / CSS、JavaScript 技术,让静态的文档也能与你一起「动」起来。

表格行分组

为满足对于产品设计文档、技术文档(如 API 接口文档)都会在同一个表格内,对不同的表格行进行分组。VLOOK™ 结合了 GFM 的表格和引用的语法,扩展支持对表格行进行分组。

在任意表格行的首列,使用 Markdown 的引用的语法>(空格),即可表示该行缩进一级,其前一行即为上一级的分组;多个>表示缩进多级,如三级缩进>>>(空格)

分级 写法举例
一级缩进 > 这是一级缩进
二级缩进 >> 这是二级缩进
三级缩进 >>> 这是三级缩进
(以此类推) <<
表格行分组举例如下:
列头1 [ ] 勾选列 列头2
普通行
普通行
普通行
[ 分组 1 ]
> 这是属于分组 1 的内容 1.1 [x] 该行是被折叠的行
> 这是属于分组 1 的内容 1.2 该行是被折叠的行
普通行
普通行
[ 分组 2 ] << <<
> 这是属于分组 2 的内容 2.1 [x] 该行为被折叠的行
> 这是属于分组 2 的内容 2.2 该行为被折叠的行
> [ 这是属于分组 2 的内容 2.3(二级分组)] [x] 该行为被折叠的行
>> 这是属于二级分组 2.3 的内容 2.3.1 该行为被折叠的行
>> [ 这是属于二级分组 2.3 的内容 2.3.2(三级分组)] << <<
>>> 这是属于三级分组 2.3.2 的内容 2.3.2.1 [x] 该行为被折叠的行
> 这是属于分组 2 的内容 2.4 该行为被折叠的行
普通行 [x] 单元格内容
普通行
普通行
普通行
普通行
普通行
普通行

支持音频、视频

音频

支持的音频格式:MP3 (.mp3)、Ogg (.ogg)、Wav (.wav)、M4a (.m4a)

语法与 Mardown 的插入图片保持一致(在标准模式控件时可支持自动题注)。
语法:![音频题注](音频URL "音频第2题注"),如:![这是音频](audio.mp3)

音频播放控件默认为:标准模式

音频播放控件默认为标准模式

音频播放控件可指定为:Mini 模式

← 点击播放

![音频内容支持定制的内容]

可定制特性 URL 参数 示例
启用 Mini 模式的播放控件 controls=mini
启用 播放/暂时 模式
(默认为 播放/结束)
pause=true
#注意#仅 Mini 模式下有效
显示音频时长 duration=true
#注意#仅 Mini 模式下有效
开启自动播放 autoplay=true
开启循环播放 loop=true 循环播放音频示例
开启预加载 preload=true 预加载音频示例

[+] 音频 URL 参数语法说明

  • 音频 URL 无参数时:先在 URL 后添加英文问号?后,再添加需要的 URL 参数: ![音频题注](xxxxx.mp3?controls=mini)
  • 音频 URL 已有参数时:多个参数间用英文特殊符号&进行分隔: ![音频题注](xxxxx.ogg?controls=mini&loop=true)

视频

支持的格式:Ogg (.ogv)、MPEG4 (.mp4)、WebM (.webm)

语法与 Mardown 的插入图片保持一致,可支持自动题注
语法:![视频题注](音频URL "视频第2题注"),如:![这是视频](video.webm)

视频示例

![视频内容支持定制的内容]

可定制特性 URL 参数 示例
开启自动播放 autoplay=true
开启循环播放 loop=true
开启预加载 preload=true 预加载视频示例
指定视频宽度 width=xxx 指定视频的宽度(单位:px)
指定视频高度 height=xxx 指定视频的高度(单位:px)

#提示#tips视频 URL 参数语法与音频一致

代码块增强

更实用、更美观的代码块样式,支持高亮当前行、一键复制代码,还能自动适配 [Dark 模式](#Dark 模式)。

#注意#须先启用显示代码块行号配置。启用方式:「Typora → 文件 → 偏好设置 → Markdown → 代码块 - 显示行号」

![VLOOK™ 的代码块示例]”语法着色器: C++”

// ================================================== //
//            VLOOK™ 支持对长代码块进行自动折叠           //
// ================================================== //

/**
 * 快速排序
 * @param arr 排序的目标数据
 * @param left 排序范围左值
 * @param right 排序范围右值
 */
void quickSort(int arr[], int left, int right) {
    int i = left, j = right, tmp, pivot = arr[(left + right) / 2];
  
    /* partition */
    while (i <= j) {
        while (arr[i] < pivot)
            i++;
        while (arr[j] > pivot)
            j--;
        if (i <= j) {
            tmp = arr[i];
            arr[i] = arr[j];
            arr[j] = tmp;
            i++;
            j--;
        }
    };

    /* recursion */
    if (left < j)
        quickSort(arr, left, j);

    if (i < right)
        quickSort(arr, i, right);
}

// ================================================== //

引用内容可设置为折叠

对 Markdown 「引用」> 引用内容进行简单的扩展,实现对引用内容的动态的折叠 / 展开操作,还可以设置默认姿势是折叠,还是展开。

举例如下:

[+] 以下是默认折叠的「引用」内容

  • 在作为折叠引子的内容前增加:[+]<空格>[-]<空格>

    • [+]指该标题下的引用内容默认为「收起」状态;
    • [-]指该标题下的引用内容默认为「展开」状态;
  • 然后换行后添加一个新的嵌套的引用块,该嵌套的引用块即为该引子对应要折叠 / 展开的内容。

[+] 可支持多重引用的折叠

[+] 这里是第三重引用折叠的内容

这是第三重引用的内容

[-] 以下是是默认展开的「引用」内容

默认为展示的引用内容

扩展的 Markdown 语法参考如下:

> [+] 我是折叠的引子
> > 我是被折叠的内容
> > 我是被折叠的内容

长内容自动折叠

文档中的长插图、长表格、长代码会占用过多的屏幕空间,通过 VLOOK™ 可以实现对这些长内容的自动折叠;

• 长图片查看示例

• 长的表格查看示例

• 长代码查看示例

文档内容检查与优化

自动识别缺失的图片

识别出无法加载的图片,并替换为图片缺失提示图,示例如下:

缺失的图片

页内链接检查

自动检查页面内部链接的正确性,若存在无效的页内链接,则通过弹窗提示。

重名章节标题检查

自动检查文档是否存在重名的标题,以提示作者检查是否会存在页内链接不能跳转到重名的标题位置的可能性。

#注意#重名章节标题的警告提示信息须启动浏览器的开发者工具或调试工具后,打开其控制台窗口进行查看。

外部链接强制在新标签打开

为提高文档阅读与交互体验,对于外链(如:http、https、ftp等),自动强制设置为在新标签页中打开。

视觉与交互

人类从来都是视觉动物,自己或他人在阅读时,让眼睛感受愉悦和美好,是一种美德、一种力量、一种信仰。

                                        ── MAX丨孟兆

欢迎屏

默认情况下,文档和插件加载过程中会自动显示欢迎屏,完成加载后,可手动关闭并显示文档。

若希望不显示,或希望在完成加载后自动关闭欢迎屏,可通过添加 URL 参数的方式进行指定,具体说明如下:

URL 参数 URL 参数取值 说明 举例
ws none 不显示欢迎屏 你的文档.html==?ws=none==
ws auto 文档和插件加载完成后,自动关闭欢迎屏 你的文档.html==?ws=auto==

Dark 模式

所有 VLOOK™ 的主题,都会自动根据浏览器的配置,自动适配显示 Light / Dark 模式,也支持手动方式进行切换。

Light / Dark 效果预览

#提示#tips如果你的图片在 Dark 模式下显得不够和谐,可以尝试选择让图片在 Dark 模式时自动反色

字体风格选择

支持 衬线非衬线 两套字体风格,可根据个人喜好进行切换,后续将会引入更多字体风格。

衬线与非衬线分别优先使用开源的 思源黑体思源宋体,建议下载安装获得最佳的视觉体验。

[+] 字体下载地址

更友好的脚注

默认情况下,Typora 导出的 HTML 在查看脚注时会在文档中来回跳转。

通过 VLOOK™ 插件优化后的脚注,可以直接在当前页面位置弹层的方式进行显示,可点击文末右上角的链接查看效果[^脚注1]

[^脚注1]: 这是 VLOOK™ 优化后的脚的信息

更美观的公式

行内公式

$\lim_{x \to \infty} \exp{-x}=0$

多行公式

$$
\mathbf{V}_1 \times \mathbf{V}_2 = \begin{vmatrix}
\mathbf{i} & \mathbf{j} & \mathbf{k} \
\frac{\partial X}{\partial u} & \frac{\partial Y}{\partial u} & 0 \
\frac{\partial X}{\partial v} & \frac{\partial Y}{\partial v} & 0 \
\end{vmatrix}
$$

打印样式适配

使用 VLOOK™ 提供的定制打印功能,可以在打印输出时自动优化页面排版和样式,以适应用打印输出。

快捷键操作

![全局快捷键]

快捷键 功能
D 开启 / 关闭 Dark 模式
O 显示 / 隐藏大纲面板
A 切换字体样式,详见字体风格选择
I 显示 / 隐藏插图导航
P 打印文档
S 打开 / 关闭聚光灯
上一章
下一章
JKHL 内容块浏览操作,详见逐段导航
ESC 关闭弹出的界面、聚光灯、内容块聚焦等

![插图导航快捷键]”注:打开插图导航后生效”

快捷键 功能
前一张插图
后一张插图

![聚光灯快捷键]”注:打开聚光灯后生效”

快捷键 功能
⇧ Shift 调整聚光灯大小

打赏

若喜欢 VLOOK™ 的话,可以请 MAX 喝杯咖啡~

a cup of MAX˚coffee

如何使用

第1步:下载、配置

  • 访问 VLOOK™ 在 GitHubGitee 的主页下载最新发布的版本;
  • 下载并安装 Typora ,启动后进入「偏好设置」,并开启以下选项,详见下图:

开启「Markdown ▸ 代码块、公式」下的所有选项

开启「Markdown ▸ Markdown 扩展语法」下的所有选项

第2步:应用主题

  • released\theme下所有 CSS 文件复制至 Typora 的主题目录( Typora「偏好设置」中点击「外观 - 打开主题目录」定位到该目录);
  • 重启 Typora ,点击菜单主题,选择以vlook-*形式命名的主题,即可启用对应的 VLOOK™ 主题样式;
  • 可基于released下的VLOOK-Document-Template.md 为模板来创建你自己的 Markdown 文档。

第3步:植入插件

  • 在 Typora 中将 Markdown 文件导出为HTML文件;
  • 打开文件released\VLOOK-plugin-for-Typora.txt,全选所有内容,并复制;
  • 用纯文件编辑器,如:记事本、Visual Studio Code,打开该导出的 HTML 文件;
  • 搜索「**<body **」,并将复制的内容粘贴到 body 标签的关闭符「**>**」之后:
    <body ...>
    ◀ ◀ ◀ 将「VLOOK-plugin-for-Typora.txt」文件的内容粘贴于此!
    ...
    </body>
  • 保存,大吉大利。

强烈建议使用 Chrome、Firefox、Edge 浏览器访问

The End

概述

编程
书名 简介 难度 感受
《从0到1:HTML+CSS快速入门》 语法简单,易于理解,稍微记一下标签的使用和
《从0到1:JavaScript快速上手》 ☆☆
《从0到1:HTML5+CSS3修炼之道》 ☆☆
《从0到1:jQuwey快速上手》 ☆☆
《JavaScript高级程序设计(第四版)》 ☆☆☆☆
《JavaScript忍者秘籍(第二版)》 ☆☆☆
历史
书名 简介 难度 感受
侦探
书名 简介 难度 感受
历史
书名 简介 难度 感受
其他
书名 简介 难度 感受
参考链接: